以下是服务端的代码:
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 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 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 11 #define EXIT_CODE 112 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 clientserver:server.c gcc -g server.c -o server
但是在执行的时候,可能有以下问题:
1.首先执行./server
2.然后执行./client& ./client & ./client&
虽然服务程序创建的子进程已经退出,但是客户端无法返回到termial中,有哪位大神知道这是为什么,请指示。
在编写此代码主要收获:
1.子进程结束的时候会产生SIGCHLD信号,父进程要捕捉此信号,执行waitpid操作,否则会产生僵尸进程,而且越来越多。
2.accept是慢系统调用,会被信号中断,并且设置errno为EINTR,代码中需要排除accept因为进程捕捉到信号而被中断的情况。
代码中还有什么问题,请各位看官多多指教。