Data Packet sockets
I don't want to talk more, so I will give Code Talker. C and listener. C.
The listener waits for packets from Port 4590 on the machine. Talker sends data packets to a certain machine, which contains the content entered by the user in the command line.
Here is listener. C:
# Include <stdio. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <string. h>
# Include <sys/types. h>
# Include <netinet/in. h>
# Include <sys/socket. h>
# Include <sys/Wait. H>
# Define myport 4950/* The port users will be sending */
# Define maxbuflen 100
Main ()
{
Int sockfd;
Struct sockaddr_in my_addr;/* My address information */
Struct sockaddr_in their_addr;/* connector's address information */
Int addr_len, numbytes;
Char Buf [maxbuflen];
If (sockfd = socket (af_inet, sock_dgram, 0) =-1 ){
Perror ("socket ");
Exit (1 );
}
My_addr.sin_family = af_inet;/* Host byte order */
My_addr.sin_port = htons (myport);/* short, network byte order */
My_addr.sin_addr.s_addr = inaddr_any;/* auto-fill with my IP */
Bzero (& (my_addr.sin_zero),;/* zero the rest of the struct */
If (BIND (sockfd, (struct sockaddr *) & my_addr, sizeof (struct sockaddr ))
\
=-1 ){
Perror ("bind ");
Exit (1 );
}
Addr_len = sizeof (struct sockaddr );
If (numbytes = recvfrom (sockfd, Buf, maxbuflen, 0 ,\
(Struct sockaddr *) & their_addr, & addr_len) =-1 ){
Perror ("recvfrom ");
Exit (1 );
}
Printf ("got packet from % s \ n", inet_ntoa (their_addr.sin_addr ));
Printf ("packet is % d bytes long \ n", numbytes );
Buf [numbytes] = '\ 0 ';
Printf ("packet contains \" % s \ "\ n", Buf );
Close (sockfd );
}
Note that we finally use sock_dgram when we call socket. At the same time, there is no need to use listen () or accept (). We are using the connectionless datagram concatenation word!
Below is talker. C:
# Include <stdio. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <string. h>
# Include <sys/types. h>
# Include <netinet/in. h>
# Include <sys/socket. h>
# Include <sys/Wait. H>
# Define myport 4950/* The port users will be sending */
Int main (INT argc, char * argv [])
{
Int sockfd;
Struct sockaddr_in their_addr;/* connector's address information */
Struct hostent * He;
Int numbytes;
If (argc! = 3 ){
Fprintf (stderr, "Usage: talker hostname message \ n ");
Exit (1 );
}
If (He = gethostbyname (argv [1]) = NULL) {/* Get the host info */
Herror ("gethostbyname ");
Exit (1 );
}
If (sockfd = socket (af_inet, sock_dgram, 0) =-1 ){
Perror ("socket ");
Exit (1 );
}
Their_addr.sin_family = af_inet;/* Host byte order */
Their_addr.sin_port = htons (myport);/* short, network byte order
*/
Their_addr.sin_addr = * (struct in_addr *) He-> h_addr );
Bzero (& (their_addr.sin_zero),;/* zero the rest of the struct */
If (numbytes = sendto (sockfd, argv [2], strlen (argv [2]), 0 ,\
(Struct sockaddr *) & their_addr, sizeof (struct sockaddr) =-1 ){
Perror ("sendto ");
Exit (1 );
}
Printf ("sent % d bytes
% S \ n ", numbytes, inet_ntoa (their_addr.sin_addr ));
Close (sockfd );
Return 0;
}
That's all. Run listener on one machine, and then run talker on another machine. Observe their communication!
In addition to the small details of the data socket connection I mentioned above, I have to say something about the data concatenation. When a speaker calls connect () when the function is used to specify the recipient's address, it can be seen that the speaker can only send and receive information to the address specified by the connect () function. Therefore, you do not need to use sendto () and recvfrom (). You can use send () and Recv () instead.
--------------------------------------------------------------------------------
Blocking
Blocking. You may have heard about it long ago. "Blocking" is the technical line of "Sleep. You may notice the listener Program It is running constantly, waiting for the arrival of data packets. Actually running is that it calls recvfrom (), and there is no data, so recvfrom () says "Block" until the arrival of data.
Many functions use blocking. Accept () is blocked, and all the Recv * () functions are blocked. They can do this because they are allowed to do so. When you call socket () to create a socket descriptor for the first time, the kernel sets it to blocking. If you do not want socket blocking, you need to call the function fcntl ():
# Include <unistd. h>
# Include <fontl. h>
.
.
Sockfd = socket (af_inet, sock_stream, 0 );
Fcntl (sockfd, f_setfl, o_nonblock );
.
.
By setting the socket to be non-blocking, You can effectively "Ask" the socket to obtain information. If you try to read information from a non-blocking socket without any data, it does not allow congestion-it will return-1 and set errno to ewouldblock.
But in general, this kind of inquiry is not a good idea. If you make your program busy waiting for the socket data to be queried, you will waste a lot of CPU time. The better solution is to use the select () Statement in the next chapter to query whether data is to be read.
--------------------------------------------------------------------------------
Select () -- Multi-Channel Synchronous I/O
Although this function is a bit strange, it is very useful. Assume that you are a server that constantly reads data from connections and listens for connection information. No problem. You may say, isn't it an accept () and two Recv? So easy, friend? What if you block it when calling accept? How can you receive Recv () data at the same time? "Use a non-blocking socket !" No! You don't want to use up all the CPUs, do you? So what should we do?
Select () allows you to monitor multiple sockets at the same time. If you want to know, it will tell you which socket is to be read, which is to be written, and which socket has exceptions ).
In other words, the following is select ():
# Include <sys/time. h>
# Include <sys/types. h>
# Include <unistd. h>
Int select (INT numfds, fd_set * readfds, fd_set * writefds, fd_set
* Required TFDs, struct timeval * timeout );
This function monitors a series of file descriptors, especially readfds, writefds, and limit TFDs. If you want to know whether you can read data from the standard input and socket descriptor sockfd, you just need to add the file descriptor 0 and sockfd to the set readfds. The parameter numfds should be equal to the value of the highest file descriptor plus 1. In this example, you should set this value to sockfd + 1. Because it must be greater than the standard input file descriptor (0 ). When the select () function returns, the value of readfds is changed to reflect which file descriptor you choose to read. You can use the macro fd_isset () mentioned below to test the function. Before we continue, let me talk about how to operate these collections. Each set type is fd_set. The following are some macro operations for this type:
Fd_zero (fd_set * Set)-clears a file descriptor set
Fd_set (int fd, fd_set * Set)-add FD to set
Fd_clr (int fd, fd_set * Set)-Remove FD from set
Fd_isset (int fd, fd_set * Set)-test whether FD is in the collection
Finally, it is a somewhat odd data structure, struct timeval. Sometimes you don't want to wait for others to send data. When nothing happens, you may want to print the string "still going..." on the terminal every 96 seconds ...". This data structure allows you to set a time. If the time is reached, and select () does not find a prepared file descriptor, it will return for you to continue processing.
The data structure struct timeval is as follows:
Struct timeval {
Int TV _sec;/* seconds */
Int TV _usec;/* microseconds */
};
Set TV _sec to the number of seconds you want to wait, and set TV _usec to the number of microseconds you want to wait. Yes, in microseconds rather than milliseconds. 1,000 microseconds equals 1 millisecond, and 1,000 milliseconds equals 1 second. That is to say, 1 second is equal to 1,000,000 microseconds. Why is the symbol "USEC" used? The letter "U" is very similar to the Greek letter Mu, while Mu indicates the meaning of "micro. Of course, the timeout value returned by a function may be the remaining time. It is possible that it depends on your UNIX operating system.
Ha! We now have a microsecond-level timer! Don't calculate it. The time slice of the standard UNIX system is 100 ms, so no matter how you set your data structure struct timeval, you have to wait that long.
There are also some interesting things: If you set the data in the data structure struct timeval to 0, select () will immediately time out, so that you can effectively poll all the file descriptors in the set. If you assign a value to NULL for the timeout parameter, it will never time out until the first file descriptor is ready. Finally, if you are not very concerned about the waiting time, assign it null.
The following code demonstrates waiting for 2.5 seconds on the standard input:
# Include <sys/time. h>
# Include <sys/types. h>
# Include <unistd. h>
# Define stdin 0/* file descriptor for standard input */
Main ()
{
Struct timeval TV;
Fd_set readfds;
TV. TV _sec = 2;
TV. TV _usec = 500000;
Fd_zero (& readfds );
Fd_set (stdin, & readfds );
/* Don't care about writefds and need TFDs :*/
Select (stdin + 1, & readfds, null, null, & TV );
If (fd_isset (stdin, & readfds ))
Printf ("A key was pressed! \ N ");
Else
Printf ("timed out. \ n ");
}
If you are on a line buffered terminal, press enter (return). Otherwise, it times out in any case.
Now, you may think that this is the way to wait for data on the datagram socket-you are right: it may be. Some UNIX systems can use this method, while others cannot. You may have to check the man page of the system before trying it.
Last thing about select (): If you have a set of characters that are listening (Listen, you can add the file descriptor of the socket to the readfds set to check whether a new connection exists.
This is what I want to talk about in the select () function.
Bibliography:
Internetworking with TCP/IP, volumes I-III by Douglas E. Comer and
David L. Steven S. Published by Prentice Hall. Second Edition isbns:
0-13-468505-9, 0-13-472242-6, 0-13-474222-2. There is a third edition
This set which covers IPv6 and IP over ATM.
Using C on the UNIX system by David A. Curry. Published
O 'Reilly & Associates, Inc. ISBN 0-937175-23-4.
TCP/IP network administration by Craig hunt. Published by O 'Reilly
& Associates, Inc. ISBN 0-937175-82-x.
TCP/IP replicated strated, Volumes 1-3 by W. Richard Steven S and Gary R.
Wright. Published by Addison Wesley. isbns: 0-201-63346-9,
0--6-63354-x, 0-201-63495-3.
UNIX network programming by W. Richard Steven S. Published
Prentice Hall. ISBN 0-13-949876-1.
On the web:
BSD sockets: a quick and dirty Primer
Http://www.cs.umn.edu /~ Bentlema/Unix/-- has; other great Unix
System Programming info, too !)
Client-server computing
Http://pandonia.canberra.edu.au/ClientServer/socket.html)
Intro to TCP/IP (gopher)
(Gopher: // gopher-chem.ucdavis.edu/11/index/internet_aw/intro_the_inter
Net/intro. to. IP /)
Internet Protocol Frequently Asked Questions (France)
Http://web.cnam.fr/Network/TCP-IP)
The UNIX socket FAQ
Http://www.ibrado.com/sock-faq)
Rfcs -- the real dirt:
RFC-768 -- the user datasync protocol (UDP)
Ftp://nic.ddn.mil/rfc/rfc768.txt)
RFC-791 -- the Internet Protocol (IP)
Ftp://nic.ddn.mil/rfc/rfc791.txt)
RFC-793 -- the Transmission Control Protocol (TCP)
Ftp://nic.ddn.mil/rfc/rfc793.txt)
RFC-854 -- the Telnet protocol
Ftp://nic.ddn.mil/rfc/rfc854.txt)
The RFC-951 -- the Bootstrap Protocol (BOOTP)
Ftp://nic.ddn.mil/rfc/rfc951.txt)
The RFC-1350 -- the Trivial File Transfer Protocol (TFTP)
Ftp://nic.ddn.mil/rfc/rfc1350.txt)