Everyone knows the compiling steps of various network server programs and knows that there are two types of network servers: cyclic services and concurrent services. Here is a summary of the source code.
First of all, the process of Loop Network Server programming is as follows: This type of server model is a typical Loop Service. Without the multi-process/thread technology, the Service throughput is limited. As you can see, if the data of the previous connection service is not sent and received, the subsequent Connections cannot be processed. Therefore, there is usually a multi-process technology that enables a new process to process a new connection, and the listening socket continues to listen.
************************ * ********************* Filename: realization of various types of TCP network server in Linux * purpose: record all kinds of tcp Service Program in Linux * wrote by: zhoulifa (zhoulifa@163.com) Zhou Lifa (http://zhoulifa.9999mb.com) linux enthusiasts Linux knowledge disseminators sohodevelopers are best at C Language * date time: 22:00:00 * Note: Anyone can copy code and use these documents at will, of course, it includes your commercial use * but follow GPL * Hope: I Hope more and more people will contribute their own strength, contribute to the development of science and technology *********************************** **********************************/
The source code of a loop TCP Service (because fork is used for multi-process services, this service is also useful in reality) as follows:
- /* ---------------------- Start of source code --------------------------------------------*/
- # 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>
- /*************************************** ******************************
- * Filename: cycletcpserver. c
- * Purpose: a circular tcp server program
- * Tidied by: zhoulifa (zhoulifa@163.com) Zhou Lifa (http://zhoulifa.9999mb.com)
- Linux enthusiasts Linux knowledge disseminators sohowhose developers are best at C Language
- * Date time: 2006-07-04 22:00:00
- * Note: Anyone can copy the code and use these documents, including your commercial use.
- * But follow the GPL
- * Thanks to: Google.com
- **************************************** *****************************/
- Int main (int argc, char ** argv)
- {
- Int sockfd, new_fd;/* listen to socket: sock_fd, data transmission socket: new_fd */
- Struct sockaddr_in my_addr;/* local address information */
- Struct sockaddr_in their_addr;/* customer address information */
- Unsigned int sin_size, myport, lisnum;
- If (argv [1]) myport = atoi (argv [1]);
- Else myport = 7838;
- If (argv [2]) lisnum = atoi (argv [2]);
- Else lisnum = 2;
- If (sockfd = socket (PF_INET, SOCK_STREAM, 0) =-1 ){
- Perror ("socket ");
- Exit (1 );
- }
- My_addr.sin_family = PF_INET;
- My_addr.sin_port = htons (myport );
- My_addr.sin_addr.s_addr = INADDR_ANY;
- Bzero (& (my_addr.sin_zero), 0 );
- If (bind (sockfd, (struct sockaddr *) & my_addr, sizeof (struct sockaddr) =-1 ){
- Perror ("bind ");
- Exit (1 );
- }
- If (listen (sockfd, lisnum) =-1 ){
- Perror ("listen ");
- Exit (1 );
- }
- While (1 ){
- Sin_size = sizeof (struct sockaddr_in );
- If (new_fd = accept (sockfd, (struct sockaddr *) & their_addr, & sin_size) =-1 ){
- Perror ("accept ");
- Continue;
- }
- Printf ("server: got connection from % s \ n", inet_ntoa (their_addr.sin_addr ));
- If (! Fork () {/* child process code segment */
- If (send (new_fd, "Hello, world! \ N ", 14, 0) =-1 ){
- Perror ("send ");
- Close (new_fd );
- Exit (0 );
- }
- }
- Close (new_fd);/* the socket is no longer required by the parent process */
- Waitpid (-1, NULL, WNOHANG);/* wait until the child process ends and clear the resources occupied by the child process */
- }
- }
- /* ---------------------- Source code end --------------------------------------------*/
Copy code
The code for a test client is as follows:
- /* ---------------------- Start of source code --------------------------------------------*/
- # Include <stdio. h>
- # Include <stdlib. h>
- # Include <errno. h>
- # Include <string. h>
- # Include <netdb. h>
- # Include <sys/types. h>
- # Include <netinet/in. h>
- # Include <sys/socket. h>
- # Define MAXDATASIZE 100/* maximum data transmission volume each time */
- /*************************************** ******************************
- * Filename: cycletcpclient. c
- * Purpose: cyclic tcp client program
- * Tidied by: zhoulifa (zhoulifa@163.com) Zhou Lifa (http://zhoulifa.9999mb.com)
- Linux enthusiasts Linux knowledge disseminators sohowhose developers are best at C Language
- * Date time: 2006-07-04 22:20:00
- * Note: Anyone can copy the code and use these documents, including your commercial use.
- * But follow the GPL
- * Thanks to: Google.com
- * Hope: more and more people are expected to contribute to the development of science and technology.
- **************************************** *****************************/
- Int main (int argc, char * argv [])
- {
- Int sockfd, numbytes;
- Char buf [MAXDATASIZE];
- Struct hostent * he;
- Struct sockaddr_in their_addr;
- Unsigned int myport;
- If (argv [2]) myport = atoi (argv [2]);
- Else myport = 7838;
- If (argc! = 3 ){
- Fprintf (stderr, "usage: % s hostname port \ n", argv [0]);
- Exit (1 );
- }
- If (he = gethostbyname (argv [1]) = NULL ){
- Herror ("gethostbyname ");
- Exit (1 );
- }
- If (sockfd = socket (PF_INET, SOCK_STREAM, 0) =-1 ){
- Perror ("socket ");
- Exit (1 );
- }
- Their_addr.sin_family = PF_INET;
- Their_addr.sin_port = htons (myport );
- Their_addr.sin_addr = * (struct in_addr *) he-> h_addr );
- Bzero (& (their_addr.sin_zero), 0 );
- If (connect (sockfd, (struct sockaddr *) & 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 \ n", buf );
- Close (sockfd );
- Return 0;
- }
- /* ---------------------- Source code end --------------------------------------------*/
Copy code
Use gcc cycletcpserver. c-o tcpserver and gcc cycletcpclient. c-o tcpclient to compile the above Code and the running status is as follows:
Administrator @ ubuzlf:/data/example/c $./tcpserver server: got connection from 127.0.0.1 server: got connection from 127.0.0.1 server: got connection from 127.0.0.1
Client running display:
Administrator @ ubuzlf:/data/example/c $./tcpclient 127.0.0.1 7838 stored ed: Hello, world!
Administrator @ ubuzlf:/data/example/c $./tcpclient 127.0.0.1 7838 stored ed: Hello, world!
Administrator @ ubuzlf:/data/example/c $./tcpclient 127.0.0.1 7838 stored ed: Hello, world!
I have to say a conceptual problem: blocking and non-blocking are in the blocking service. What happens when the server runs an accept statement without a Client Connecting to the service request? Then the server stops waiting for the connection service request on the accept statement. Similarly, when the program runs to receive the data statement recv, if no data can be read, the program will also stop on the receiving statement. This is called blocking ). However, if you want the server to check whether a client is waiting for a connection, you can accept the connection. Otherwise, you can continue to do other things by setting the socket to a non-blocking method: the non-blocking socket enables the accept call to return immediately when no client is waiting. By setting the socket as a non-blocking method, you can implement "polling" Several sockets. When an attempt is made to read data from a non-blocking socket without data waiting for processing, the function will return immediately, and the return value is set to-1, and errno is set to EWOULDBLOCK. However, this "Round Robin" will make the CPU in a busy waiting mode, thus reducing performance. Considering this situation, if you want the server to listen to Connection Service requests and read data from established connections, you may think of using one accept statement and multiple recv () statements, however, since both accept and recv are blocked, this idea is obviously not successful. Calling a non-blocking socket will greatly waste system resources. The call to select () can effectively solve this problem. It allows you to hook the process itself and enable the system kernel to listen to any activity of a set of file descriptors required by the system kernel, as long as the activity is confirmed on any monitored file descriptor, the select () call will return information indicating that the file descriptor is prepared, so as to select random changes for the process, the CPU overhead does not need to be wasted because the process itself tests the input.
Second, the concurrent server, in the above cycletcpserver. in c, fork technology can also be called a concurrent server, but this server is not a real I/O multiplexing concurrent server, and because it does not handle blocking problems, there are various problems in practical application.
A typical single-process concurrent server with IO multiplexing is as follows:/* IO multiplexing concurrent service flowchart */The following is a source program that demonstrates IO multiplexing and is a port forwarding program, however, it is very useful. In actual applications, all types of proxy software or port ing software are based on such code, such as Windows WinGate and WinProxy. The source code is as follows:
- /* ---------------------- Start of source code --------------------------------------------*/
- # Include <stdlib. h>
- # Include <stdio. h>
- # Include <unistd. h>
- # Include <sys/time. h>
- # Include <sys/types. h>
- # Include <string. h>
- # Include <signal. h>
- # Include <sys/socket. h>
- # Include <netinet/in. h>
- # Include <arpa/inet. h>
- # Include <errno. h>
- Static int forward_port;
- # Undef max
- # Define max (x, y) (x)> (y )? (X): (y ))
- /************************* About this document *********** *************************
- * Filename: tcpforwardport. c
- * Purpose: demonstrate the usage of select, which is an excellent agent software core and used for port ing.
- * Tidied by: zhoulifa (zhoulifa@163.com) Zhou Lifa (http://zhoulifa.9999mb.com)
- Linux enthusiasts Linux knowledge disseminators sohowhose developers are best at C Language
- * Date time: 2006-07-05 19:00:00
- * Note: Anyone can copy the code and use these documents, including your commercial use.
- * But follow the GPL
- * Thanks to: Paul Sheer Thanks to Paul Sheer for providing the source code in the select_tut man manual.
- * Hope: more and more people are expected to contribute to the development of science and technology.
- **************************************** *****************************/
- Static int listen_socket (int listen_port ){
- Struct sockaddr_in;
- Int s;
- Int yes;
- If (s = socket (AF_INET, SOCK_STREAM, 0) <0 ){
- Perror ("socket ");
- Return-1;
- }
- Yes = 1;
- If (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) & yes, sizeof (yes) <
- 0 ){
- Perror ("setsockopt ");
- Close (s );
- Return-1;
- }
- Memset (& a, 0, sizeof ());
- A. sin_port = htons (listen_port );
- A. sin_family = AF_INET;
- If (bind (s, (struct sockaddr *) & a, sizeof (a) <0 ){
- Perror ("bind ");
- Close (s );
- Return-1;
- }
- Printf ("accepting connections on port % d \ n", (int) listen_port );
- Listen (s, 10 );
- Return s;
- }
- Static int connect_socket (int connect_port, char * address ){
- Struct sockaddr_in;
- Int s;
- If (s = socket (AF_INET, SOCK_STREAM, 0) <0 ){
- Perror ("socket ");
- Close (s );
- Return-1;
- }
- Memset (& a, 0, sizeof ());
- A. sin_port = htons (connect_port );
- A. sin_family = AF_INET;
- If (! Inet_aton (address, (struct in_addr *) & a. sin_addr.s_addr )){
- Perror ("bad IP address format ");
- Close (s );
- Return-1;
- }
- If (connect (s, (struct sockaddr *) & a, sizeof (a) <0 ){
- Perror ("connect ()");
- Shutdown (s, SHUT_RDWR );
- Close (s );
- Return-1;
- }
- Return s;
- }
- # Define SHUT_FD1 {\
- If (fd1> = 0 ){\
- Shutdown (fd1, SHUT_RDWR );\
- Close (fd1 );\
- Fd1 =-1 ;\
- }\
- }
- # Define SHUT_FD2 {\
- If (fd2> = 0 ){\
- Shutdown (fd2, SHUT_RDWR );\
- Close (fd2 );\
- Fd2 =-1 ;\
- }\
- }
- # Define BUF_SIZE 1024
- Int main (int argc, char ** argv ){
- Int h;
- Int fd1 =-1, fd2 =-1;
- Char buf1 [BUF_SIZE], buf2 [BUF_SIZE];
- Int buf1_avail, buf1_written;
- Int buf2_avail, buf2_written;
- If (argc! = 4 ){
- Fprintf (stderr, "Usage \ n \ tfwd \ n ");
- Exit (1 );
- }
- Signal (SIGPIPE, SIG_IGN );
- Forward_port = atoi (argv [2]);
- /* Create a listener socket */
- H = listen_socket (atoi (argv [1]);
- If (h <0) exit (1 );
- For (;;){
- Int r, nfds = 0;
- Fd_set rd, wr, er;
- FD_ZERO (& rd );
- FD_ZERO (& wr );
- FD_ZERO (& er );
- FD_SET (h, & rd );
- /* Put the listening socket and the readable socket together into the select readable handle list */
- Nfds = max (nfds, h );
- If (fd1> 0 & buf1_avail <BUF_SIZE ){
- FD_SET (fd1, & rd );
- Nfds = max (nfds, fd1 );
- }
- If (fd2> 0 & buf2_avail <BUF_SIZE ){
- FD_SET (fd2, & rd );
- Nfds = max (nfds, fd2 );
- }
- /* Put the writeable socket two together into the select writable handle list */
- If (fd1> 0 & buf2_avail-buf2_written> 0 ){
- FD_SET (fd1, & wr );
- Nfds = max (nfds, fd1 );
- }
- If (fd2> 0 & buf1_avail-buf1_written> 0 ){
- FD_SET (fd2, & wr );
- Nfds = max (nfds, fd2 );
- }
- /* Put the two sockets with abnormal data into the select exception handle list */
- If (fd1> 0 ){
- FD_SET (fd1, & er );
- Nfds = max (nfds, fd1 );
- }
- If (fd2> 0 ){
- FD_SET (fd2, & er );
- Nfds = max (nfds, fd2 );
- }
- /* Start select */
- R = select (nfds + 1, & rd, & wr, & er, NULL );
- If (r =-1 & errno = EINTR) continue;
- If (r <0 ){
- Perror ("select ()");
- Exit (1 );
- }
- /* Process new connections */
- If (FD_ISSET (h, & rd )){
- Unsigned int l;
- Struct sockaddr_in client_address;
- Memset (& client_address, 0, l = sizeof (client_address ));
- R = accept (h, (struct sockaddr *) & client_address, & l );
- If (r <0 ){
- Perror ("accept ()");
- } Else {
- /* Close the original connection, use the new connection as fd1, and connect to the new target fd2 */
- SHUT_FD1;
- SHUT_FD2;
- Buf1_avail = buf1_written = 0;
- Buf2_avail = buf2_written = 0;
- Fd1 = r;
- Fd2 = connect_socket (forward_port, argv [3]);
- If (fd2 <0 ){
- SHUT_FD1;
- } Else
- Printf ("connect from % s \ n", inet_ntoa (client_address.sin_addr ));
- }
- }
- /* NB: read oob data before normal reads */
- If (fd1> 0)
- If (FD_ISSET (fd1, & er )){
- Char c;
- Errno = 0;
- R = recv (fd1, & c, 1, MSG_OOB );
- If (r <1 ){
- SHUT_FD1;
- } Else
- Send (fd2, & c, 1, MSG_OOB );
- }
- If (fd2> 0)
- If (FD_ISSET (fd2, & er )){
- Char c;
- Errno = 0;
- R = recv (fd2, & c, 1, MSG_OOB );
- If (r <1 ){
- SHUT_FD1;
- } Else
- Send (fd1, & c, 1, MSG_OOB );
- }
- /* NB: read data from fd1 */
- If (fd1> 0)
- If (FD_ISSET (fd1, & rd )){
- R = read (fd1, buf1 + buf1_avail, BUF_SIZE-buf1_avail );
- If (r <1 ){
- SHUT_FD1;
- } Else
- Buf1_avail + = r;
- }
- /* NB: read data from fd2 */
- If (fd2> 0)
- If (FD_ISSET (fd2, & rd )){
- R = read (fd2, buf2 + buf2_avail, BUF_SIZE-buf2_avail );
- If (r <1 ){
- SHUT_FD2;
- } Else
- Buf2_avail + = r;
- }
- /* NB: write data to fd1 */
- If (fd1> 0)
- If (FD_ISSET (fd1, & wr )){
- R = write (fd1, buf2 + buf2_written, buf2_avail-buf2_written );
- If (r <1 ){
- SHUT_FD1;
- } Else
- Buf2_written + = r;
- }
- /* NB: write data to fd1 */
- If (fd2> 0)
- If (FD_ISSET (fd2, & wr )){
- R = write (fd2, buf1 + buf1_written, buf1_avail-buf1_written );
- If (r <1 ){
- SHUT_FD2;
- } Else
- Buf1_written + = r;
- }
- /* Check if write data has caught read data */
- If (buf1_written = buf1_avail) buf1_written = buf1_avail = 0;
- If (buf2_written = buf2_avail) buf2_written = buf2_avail = 0;
- /* One side has closed the connection, keep writing to the other side until empty */
- If (fd1 <0 & buf1_avail-buf1_written = 0 ){
- SHUT_FD2;
- }
- If (fd2 <0 & buf2_avail-buf2_written = 0 ){
- SHUT_FD1;
- }
- }
- Return 0;
- }
- /* ---------------------- Source code end --------------------------------------------*/