[Collection] In-depth "Network Socket Programming Guide"

xiaoxiao2021-03-06  40

Generally, there is only one server in the server, which uses fork () to handle the connection between multiple customers. The basic program is: the server waits for a connection, accepts the connection, and then a child process processes it. This is the next chapter of our examples.

-------------------------------------------------- ------------------------------

Simple server

All of this server does send a string "Hello, World! / N" on streaming. If you want to test this program, you can run the program on a machine and then log in on another machine:

$ Telnet remotehostname 3490

RemotehostName is the name of the machine running.

Server code:

#include

#include

#include

#include

#include

#include

#include

#include

#define myport 3490 / * Defines the user connection port * /

#define backlog 10 / * How much waiting for connection control * /

Main ()

{

INT SOCKFD, New_FD; / * Listen on Sock_fd, New Connection On New_FD

* /

Struct SockAddr_in my_addr; / * my address information * /

Struct SockAddr_in their_addr; / * connector's address information * /

INT SIN_SIZE;

IF ((SockFD = Socket (AF_INET, SOCK_STREAM, 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);} if (listen (sockfd, backlog) == -1 ) {PERROR ("listen"); exit (1);}

While (1) {/ * main accept () loop * / sin_size = sizeof (struct sockaddr_in); if ((new_fd = accept (sockfd, (strunt socketdr *)) == -1) {PERROR "accept"); Continue;} Printf ("Server: Got Connection from% S / N", / inet_ntoa (their_addr.sin_addr)); if (! fork ()) {/ * this is the child process * / if ( Send (new_fd, "hello, world! / n", 14, 0) == -1) PERROR ("send"); close (new_fd); exit (0);} close (new_fd); / * Parent doesn ' T NEED THIS * / WHILE (Waitpid (-1, null, wnohang> 0); / * Clean up child processes * /}} If you are very picky, you must not satisfy all my code is in a big main. () In the function. If you don't like it, you can divide more points. -------------------------------------------------- -------------------------------------------------- ------------------------ Simple customer program This program is simpler than the server. All of this program is connected to the host specified in the command line through the 3490 port, and then get the string sent by the server. Customer code: #include #include #include #include #include #include # Include #include #define port 3490 / * Client connection remote host port * / #define maxDataSize 100 / * Maximum byte you can receive * / int Main (int argc, char * argv []) {int sockfd, numbytes; char buf [MAXDATASIZE]; struct hostent * he; struct sockaddr_in their_addr; / * connector's address information * / if (! argc = 2) {fprintf (stderr, "usage: client hostname / n"); exit (1);} if ((he = gethostByname) == null) {/ * get the host info * / human ("gethostbyname"); exit (1); }

IF ((SOCKFD = SOCKET (AF_INET, SOCK_STREAM, 0) == -1) {Perror ("socket"); exit (1);} their_addr.sin_family = AF_INET; / * HOST BYTE ORDER * / THEIR_ADDR.SIN_PORT = Htons (port); / * short, network byte order * / their_addr.sin_addr = * (struct in_addr *) HE-> h_addr); Bzero (& (THEIR_ADDR.SIN_ZERO ,; / * Zero the rest of the structure * / IF (Connect (STRUCKD, STRUCKADDR *) & THEIR_ADDR, SIZEOF (STRUCT SOCKADDR)) == -1) {Perror ("Connect"); exit (1);} if ((NumBytes = Recv (Sockfd, BUF, MaxDataSize, 0)) == -1) {Perror ("RECV"); exit (1);} buf [numbytes] = '/ 0'; Printf ("Received:% S", BUF); Close (SockFD) Return 0;} Note that if you run a client before running the server, Connect () will return "Connection Refuse" information, which is very useful. ------------------ -------------------------------------------------- -------------------------------------------------- -

Packets Sockets I don't want to talk more, so I give the code Talker.c and Listener.c. Listener Wait for packets from port 4590 on the machine. Talker sends a packet to a certain machine that contains the contents of the user entered in the command line.

Here is listener.c: #include #include #include #include #include #include #include #Define myport 4950 / * the port user maxbuffling to * / #define maxbufflen 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 = incdr_any ; / * Auto-fill with my ip * / bzero (& (my_addr.sin_zero) ,; / * Zero the rest of the structure * / if (bind (STRUCKFD, STRUCT SOCKADDR *) & my_addr, Sizeof (Struct SockAddr)) / == -1) {Perror ("bind"); exit (1);} addr_len = size OF (struct sockaddr); if ((NumBytes = Recvfrom (SockFD, BUF, Maxbufflen, 0, / (Struct Sockaddr *)) == -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 contacts / "% s /" / n ", buf); Close (SockFD);} Note that in our call socket (), we finally used Sock_DGRAM. At the same time, there is no need to use listen () or accept ().

We are using unconnected datagram sleeves! The following is Talker.c: #include #include #include #include #include #include #include #include #define myport 4950 / * the port user (int Argc, char * argv [ion sockfd) Struct SockAddr_in their_addr; / * connector's address * he; int numBytes; if (Argc! = 3) {fprintf (stderr, "usage: talker hostname message / n"); exit (1);}

IF ((He = gethostByname) == null) {/ * get the host info * / human ("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 TO% S / N", NumBytes, INET_NTOA (THEIR_ADDR.SIN_ADDR)); Close (sockfd);} This is all. Run listner on a machine, then run Talker on another machine. Observe their communication! In addition to some of the data sockets I mentioned above In addition to the small details of the connection, I have to say some, when a speaker calls the connect () function and specifies the recipient's address, from this point, the speaker can only go to Connect () The address specified by the function is sent and received. So you don't need to use Sendto () and Recvfrom (), you can use Send () and Recv () instead. ----------- -------------------------------------------------- ------------------- Blocking blocking, you may have heard it. "Block" is "Sleep" technology, you may notice the listener program run in front. It keeps running there, waiting for the packet's arrival. The actual run is that it calls Recvfrom (), then there is no data, so the recvfrom () says "block" until the arrival of the data. Many functions Using blockage. Accept () blocking, all RECV * () functions block. The reason why they can do this is because they are allowed to do so. When you first call socket () to build a set of sets, the kernel is set to block it. If you don't want to block the block, you have to call the function fcntl (): #include #include .. Sockfd = socket (AF_INET, SOCK_STREAM, 0); FCNTL (SockFD, F_Setfl, O_nonblock);. By setting the socket as non-blocking, you can effectively "inquire" socket to get information. If you try to read information from a non-blocking socket and there is no data, it does not allow blocking - it will return -1 and set errno to Ewouldblock. But in general, this kind of inquiry is not a good idea. If you let your program query the data of the socket in a busy, you will waste a lot of CPU time. Better solution is to use the selection () to check if there is data to read.

-------------------------------------------------- ------------------------------ SELECT () - Multi-channel synchronization I / O Although this function is a bit strange, it is very it works. Assuming this situation: You are a servers, you keep reading the information on the listening connection while talking on the connection from the connection. No problem, you may say, isn't it an accept () and two RECV ()? Is this easy, friend? If you block the accept ()? How do you attach the RECV () data ? "Use non-blocking sockets!" No! You don't want to exhaust all CPUs? So, how is it? Select () allows you to monitor multiple sockets at the same time. If you want to know, then it will tell you which socket is ready to read, which is ready to write, which socket has an exception. Gossip less, below is select (): #include #include #include int result (int Numfds, fd_set * readfds, fd_set * writefds, fd_set * ExceptFDS, Struct TimeVal * Timeout; This function monitors a series of file descriptors, especially READFDS, WRITEFDS, and ExcePTFDS. If you want to know if you can read the data from the standard input and socket descriptor SockFD, you only need to add file descriptor 0 and SockFD to the collection 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 larger than the standard input file descriptor (0). When the function select () is returned, the value of the readfds is modified to reflect which file descriptor you choose can read. You can test with the macro fd_isset () told below. Before we continue, let me talk about how to operate these collections. Each collection type is fd_set. There are some macros to operate on this type: fd_zero (fd_set * set) - Clear a file descriptor set fd_set (int FD, fd_set * set) - Add FD to Collect FD_CLR (int FD, FD_SET * SET) - From Collection Transfer to FD FD_ISSET (int FD, FD_SET * SET) - Test if the FD is finally in the collection, is a bit weird data structure Struct TimeVal. Sometimes you don't want to wait for others to send data. Maybe there is no matter what happened, you also want to print strings "Still Going ..." every 96 seconds. This data structure allows you to set a time, if time is, and select () has not found a ready-to-face descriptor, which will return to let you continue processing. The data structure Struct Timeval is this: struct timeval {int TV_sec; / * seconds * / int TV_usec; ​​/ * microseconds * /}; simply set TV_sec to you want to wait, set TV_USEC to you want to wait The number of seconds can be. Yes, it is microseconds instead of milliseconds. 1,000 microseconds or equal to 1 millisecond, 1,000 milliseconds is equal to 1 second. That is, 1 second is equal to 1,000,000 microseconds.

转载请注明原文地址:https://www.9cbs.com/read-55158.html

New Post(0)