以下是服务端的代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <sys/types.h> 5 #include <sys/wait.h> 6 #include <netinet/in.h> 7 #include <arpa/inet.h> 8 #include <unistd.h> 9 #include <errno.h> 10 #include <signal.h> 11 #include <sys/socket.h> 12 13 #define EXIT_CODE 1 14 15 void handler (int sig); 16 17 int main () 18 { 19 int server_fd; 20 int client_fd; 21 int result; 22 struct sockaddr_in addr_server; 23 struct sockaddr_in addr_client; 24 int len_server; 25 int len_client; 26 char *message = "this message comes from aliyun\n"; 27 pid_t pid_child; 28 struct sigaction action; 29 30 /* 31 *when the child processes exit, 32 *it will product a SIGCHLD signal, 33 *the parent process will catch it, 34 *and run handler function to recycle resource. 35 */ 36 action.sa_handler = handler; 37 sigemptyset (&action.sa_mask); 38 action.sa_flags = 0; 39 40 if (sigaction (SIGCHLD,&action,NULL) == -1) { 41 perror ("sigaction"); 42 exit (EXIT_CODE); 43 } 44 45 /*create a socket*/ 46 server_fd = socket (AF_INET,SOCK_STREAM,0); 47 if (server_fd == -1) { 48 perror ("socket"); 49 exit (EXIT_CODE); 50 } 51 52 if (setsockopt (server_fd, 53 SOL_SOCKET, 54 SO_REUSEADDR, 55 &result, 56 sizeof (result)) < 0) { 57 perror ("setsockopt"); 58 exit (EXIT_CODE); 59 } 60 61 /*set ip address and port*/ 62 addr_server.sin_family = AF_INET; 63 addr_server.sin_addr.s_addr = htonl (INADDR_ANY); 64 addr_server.sin_port = htons (9375); 65 66 /*bind a socket with address*/ 67 len_server = sizeof (addr_server); 68 if (bind (server_fd, 69 (struct sockaddr *) &addr_server, 70 len_server) == -1) 71 { 72 perror ("bind"); 73 exit (EXIT_CODE); 74 } 75 76 /*create pending queue and set pending number*/ 77 if (listen (server_fd,20) == -1) { 78 perror ("listen"); 79 exit (EXIT_CODE); 80 } 81 82 while (1) { 83 len_client = sizeof (addr_client); 84 /* 85 *the system call accept will be interrupted by signal in linux, 86 *and the erron will be set to EINTR, 87 *so if the system call accept runs failed, 88 *we should recall it inorder to clear the effect of signal. 89 */ 90 91 /* 92 *in this program, when a child process returns, 93 *the child process will send a signal named SIGCHLD to parent process 94 *and the signal parent process received will affect the system call accept 95 */ 96 while (1) { 97 client_fd = accept (server_fd, 98 (struct sockaddr *) &addr_client, 99 &len_client); 100 if (client_fd == -1 && errno == EINTR) { 101 continue; 102 } else if (client_fd > 0) { 103 break; 104 } else { 105 perror ("connect"); 106 exit (EXIT_CODE); 107 } 108 } 109 110 pid_child = fork (); 111 if (pid_child > 0) { 112 /*this is parent*/ 113 sleep (5); 114 close (client_fd); 115 continue; 116 } else { 117 /*this is child*/ 118 char buffer[4096]; 119 int connect_fd = client_fd; 120 struct sockaddr_in *p_addr = (struct sockaddr_in *) malloc (sizeof (addr_client)); 121 memcpy (p_addr,&addr_client,len_client); 122 result = read (connect_fd,buffer,4095); 123 if (result == -1) { 124 printf ("error in reading data\n"); 125 exit (EXIT_CODE); 126 } else if (result == 0) { 127 printf ("there is no data comes\n"); 128 buffer[0] = '\0'; 129 } else { 130 printf ("client says:%s\n",buffer); 131 buffer[0] = '\0'; 132 } 133 134 int count = 5; 135 while (count --) { 136 write (connect_fd,"welcome to aliyun\n",18); 137 sleep (1); 138 } 139 140 printf ("complete!\n"); 141 printf ("child process %d exit\n",getpid ()); 142 close (connect_fd); 143 break; 144 } 145 } 146 147 return 0; 148 } 149 150 void handler (int sig) 151 { 152 pid_t pid; 153 if ((pid = waitpid (0,NULL,0)) == (pid_t) -1) { 154 perror ("wait"); 155 exit (EXIT_CODE); 156 } else { 157 printf ("SIGCHLD HANDLER:already recycle child process:%d\n",pid); 158 } 159 } 160 161 162
以下是客户端代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <arpa/inet.h> 4 #include <sys/socket.h> 5 #include <netinet/in.h> 6 #include <sys/types.h> 7 #include <unistd.h> 8 #include <errno.h> 9 #include <string.h> 10 11 #define EXIT_CODE 1 12 13 int main () 14 { 15 int sockfd; 16 int len = 0; 17 struct sockaddr_in address; 18 int result = 0; 19 char ch = 'A'; 20 char buffer[4096]; 21 22 printf ("this is only a test between fedora and aliyun\n"); 23 24 /*create a socket*/ 25 sockfd = socket (AF_INET,SOCK_STREAM,0); 26 if (sockfd == -1) { 27 perror ("socket"); 28 exit (EXIT_CODE); 29 } 30 31 /*set up ip address and communication port*/ 32 address.sin_family = AF_INET; 33 address.sin_addr.s_addr = inet_addr ("127.0.0.1"); 34 address.sin_port = htons (9375); 35 36 /*get communication with server port*/ 37 len = sizeof (address); 38 if (connect (sockfd,(struct sockaddr*) &address,len) < 0) { 39 perror ("connect"); 40 exit (EXIT_CODE); 41 } 42 43 /*display having connected with server*/ 44 printf ("%s\n","connected with 127.0.0.1"); 45 printf ("Now please input your message!\n"); 46 47 /*communicate with server*/ 48 /* 49 while (1) { 50 51 if (fgets (buffer,4095,stdin) == NULL) { 52 buffer[0] = '\0'; 53 fflush (stdin); 54 printf ("an error occcured while input characters!\n"); 55 printf ("please input again\n"); 56 } else { 57 break; 58 } 59 } */ 60 strcpy (buffer,"hello aliyun"); 61 write (sockfd,buffer,strlen (buffer)); 62 63 while (1) { 64 result = read (sockfd,buffer,4095); 65 if (result == -1) { 66 printf ("server port has closed connection\n"); 67 break; 68 } else if (result == 0) { 69 break; 70 } else { 71 printf ("msg from 127.0.0.1:%s\n",buffer); 72 } 73 } 74 close (sockfd); 75 printf ("complete!\n"); 76 return 0; 77 }
写了一个极简的Makefile:
client:client.c gcc -g client.c -o client server:server.c gcc -g server.c -o server
但是在执行的时候,可能有以下问题:
1.首先执行./server
2.然后执行./client& ./client & ./client&
虽然服务程序创建的子进程已经退出,但是客户端无法返回到termial中,有哪位大神知道这是为什么,请指示。
在编写此代码主要收获:
1.子进程结束的时候会产生SIGCHLD信号,父进程要捕捉此信号,执行waitpid操作,否则会产生僵尸进程,而且越来越多。
2.accept是慢系统调用,会被信号中断,并且设置errno为EINTR,代码中需要排除accept因为进程捕捉到信号而被中断的情况。
代码中还有什么问题,请各位看官多多指教。