Socket programming practices in Linux (3) Port multiplexing and P2P multi-process servers

Source: Internet
Author: User

Socket programming practices in Linux (3) Port multiplexing and P2P multi-process servers
Socket port multiplexing first, why use socket port multiplexing? If you have encountered this problem: After the server program is restarted, it cannot be connected. It takes some time to connect to the server? 1. A listener (listen) server has started 2. when a client has a connection request, the server generates a sub-process to process the client. 3. the master process of the server is terminated, but the sub-process still occupies the connection to process the client. although the sub-process is terminated, because the sub-process is not terminated, the reference count of the socket will not be 0, so the socket will not be closed. 4. server Program Restart. At this time, because the port is occupied, you cannot re-bind it. This is also one of the reasons for designing the TIME_WAIT status. Int getsockopt (int sockfd, int level, int optname, void * optval, socklen_t * optlen); int setsockopt (int sockfd, int level, int optname, const void * optval, socklen_t optlen); SO_REUSEADDR allows multiple IP addresses to be bound to the same port, as long as these IP addresses are different. The server tries its best to use SO_REUSEADDR. Before binding, call setsockopt to set the SO_REUSEADDR socket option. This option saves the server from waiting for the TIME_WAIT status to disappear.

int setsockopt(      SOCKET s,      int level,      int optname,      const char* optval,      int optlen  );  

 

S (socket): points to an open set of Interface Description level: (level): specifies the type of the Option Code. SOL_SOCKET: Basic set interface IPPROTO_IP: IPv4 set interface IPPROTO_IPV6: IPv6 set interface IPPROTO_TCP: TCP set interface optname (option name): Option name optval (option value ): is a pointer type pointing to a variable: integer, set interface structure, other structure types: linger {}, timeval {} optlen (Option Length): The optval size before bind add source code, port multiplexing is supported:
       int on = 1;    if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,                   &on,sizeof(on)) == -1)        err_exit("setsockopt SO_REUSEADDR error");    

 

In addition, I think of a problem: Because SO_REUSEADDR is used to restart the server, the server with no options will generate a new socket connection after accept, will the connection be allocated a new port? After practice, I found that these new socket connections are consistent with the bind port !! Can a port be bound to multiple sockets? Of course not. The following is an analysis: first, a port must be bound to only one socket. In my opinion, the port on the server has been bound to the object described by the listening socket socetfd during bind. The new socket object created by the accept function does not actually occupy the port, instead, the local IP address and port number of socetfd are copied, And the IP address and port number of the connected client are recorded. Which socket object does the client communicate with when sending data? The data sent by the client can be divided into two types: connection requests and data transmission after a connection is established. The TCP/IP protocol stack maintains a receiving and sending buffer zone. After receiving data packets from the client, the server's TCP/IP protocol stack should handle the following, the data is sent to the socetfd socket listening to the connection request port for accept processing. If the client data packet has been connected, the data is placed in the receiving buffer. In this way, when the server needs to read data from the specified client, then, the socketfd_new socket can be used to obtain the specified data in the buffer through the recv or read function (because the socket object represented by socketfd_new records the Client IP address and port, so it can be identified ). To solve this problem, refer to the blog http://ticktick.blog.51cto.com/823160/779866 to deal with multi-Client Connections:
Void echo (int clientfd); int main () {int listenfd = socket (AF_INET, SOCK_STREAM, 0); if (listenfd =-1) ERR_EXIT ("socket error "); int on = 1; if (setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, & on, sizeof (on) =-1) // restart the server, port multiplexing ERR_EXIT ("setsockopt SO_REUSEADDR error"); struct sockaddr_in addr; addr. sin_family = AF_INET; addr. sin_port = htons (8001); addr. sin_addr.s_addr = htonl (INADDR_ANY); if (bind (listenfd, (const struct sockaddr *) & addr, sizeof (addr) =-1) ERR_EXIT ("bind error "); if (listen (listenfd, SOMAXCONN) =-1) ERR_EXIT ("listen error"); struct sockaddr_in clientAddr; socklen_t addrLen = sizeof (clientAddr); while (true) {int clientfd = accept (listenfd, (struct sockaddr *) & clientAddr, & addrLen); if (clientfd =-1) ERR_EXIT ("accept error "); // print the customer IP address and port number cout <"Client information:" <inet_ntoa (clientAddr. sin_addr) <"," <ntohs (clientAddr. sin_port) <endl; pid_t pid = fork (); if (pid =-1) ERR_EXIT ("fork error"); else if (pid> 0) close (clientfd); // The sub-process processing link else if (pid = 0) {close (listenfd); echo (clientfd); // The sub-process must exit, otherwise, the sub-process will return to accept exit (EXIT_SUCCESS) ;}}close (listenfd) ;}void echo (int clientfd) {char buf [512] = {0}; int readBytes; while (readBytes = read (clientfd, buf, sizeof (buf)> 0) {cout <buf; if (write (clientfd, buf, readBytes) =-1) ERR_EXIT ("write socket error"); memset (buf, 0, sizeof (buf ));} if (readBytes = 0) {cerr <"client connect closed... "<endl; close (clientfd);} else if (readBytes =-1) ERR_EXIT (" read socket error ");}

 

The implementation of a simple P2P chat program both the server and client have two processes: (1) the parent process reads data from the socket and writes it to the terminal, because the parent process uses the blocking version called by the read system, if there is no data in the socket, the parent process will be blocked all the time. If the read returns 0, the peer connection is closed, the parent process sends a SIGUSR1 signal to the child process and notifies the child process to exit. (2) The child process reads data from the keyboard and writes the data to the socket. If there is no data on the keyboard, fgets calls will be blocked all the time;
// Server code void sigHandler (int signo) {cout <"recv a signal =" <signo <endl; exit (EXIT_SUCCESS);} int main () {int listenfd = socket (AF_INET, SOCK_STREAM, 0); if (listenfd =-1) ERR_EXIT ("socket error"); int on = 1; if (setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, & on, sizeof (on) =-1) ERR_EXIT ("setsockopt SO_REUSEADDR error"); struct sockaddr_in addr; addr. sin_family = AF_INET; addr. si N_port = htons (8001); addr. sin_addr.s_addr = htonl (INADDR_ANY); if (bind (listenfd, (const struct sockaddr *) & addr, sizeof (addr) =-1) ERR_EXIT ("bind error "); if (listen (listenfd, SOMAXCONN) =-1) ERR_EXIT ("listen error"); struct implements clientAddr; socklen_t addrLen = sizeof (clientAddr); int clientfd = accept (listenfd, (struct sockaddr *) & clientAddr, & addrLen); if (clientfd =-1) ERR_EXIT ("Accept error"); close (listenfd); // print the Client IP address and port number cout <"Client information:" <inet_ntoa (clientAddr. sin_addr) <"," <ntohs (clientAddr. sin_port) <endl; char buf [512] = {0}; pid_t pid = fork (); if (pid =-1) ERR_EXIT ("fork error "); // parent process: socket-> terminal else if (pid> 0) {int readBytes; while (readBytes = read (clientfd, buf, sizeof (buf)> 0) {cout <buf; memset (buf, 0, sizeof (bu F);} if (readBytes = 0) cout <"client connect closed... \ nserver exiting... "<endl; else if (readBytes =-1) ERR_EXIT (" read socket error "); // notifies the sub-process to exit kill (pid, SIGUSR1 );} // sub-process: keyboard-> socket else if (pid = 0) {signal (SIGUSR1, sigHandler); while (fgets (buf, sizeof (buf), stdin )! = NULL) {if (write (clientfd, buf, strlen (buf) =-1) err_exit ("write socket error"); memset (buf, 0, sizeof (buf) ;}} close (clientfd); exit (EXIT_SUCCESS);} // client code and description int main () {int sockfd = socket (AF_INET, SOCK_STREAM, 0); if (sockfd =-1) ERR_EXIT ("socket error"); // enter the server port number and IP address struct sockaddr_in serverAddr; serverAddr. sin_family = AF_INET; serverAddr. sin_port = htons (8001); serverAdd R. sin_addr.s_addr = inet_addr ("127.0.0.1"); if (connect (sockfd, (const struct sockaddr *) & serverAddr, sizeof (serverAddr) =-1) ERR_EXIT ("connect error"); char buf [512] = {0}; pid_t pid = fork (); if (pid =-1) ERR_EXIT ("fork error"); // parent process: socket-> terminal else if (pid> 0) {int readBytes; while (readBytes = read (sockfd, buf, sizeof (buf)> 0) {cout <buf; memset (buf, 0, sizeof (buf ));} If (readBytes = 0) cout <"server connect closed... \ nclient exiting... "<endl; else if (readBytes =-1) ERR_EXIT (" read socket error "); kill (pid, SIGUSR1);} // sub-process: keyboard-> socket else if (pid = 0) {signal (SIGUSR1, sigHandler); while (fgets (buf, sizeof (buf), stdin )! = NULL) {if (write (sockfd, buf, strlen (buf) =-1) ERR_EXIT ("write socket error"); memset (buf, 0, sizeof (buf) ;}} close (sockfd); exit (EXIT_SUCCESS );}

 


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.