多进程回声服务器/客户端【linux】
并发服务器端
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <sys/wait.h> 4 #include <cstring> 5 #include <arpa/inet.h> 6 #include <signal.h> 7 #include <cstdlib> 8 #include <iostream> 9 using namespace std; 10 void child_over(int sig)//信号处理器 11 { 12 int state; 13 int child_pid = waitpid(-1, &state, WNOHANG); 14 if(WIFEXITED(state)) 15 { 16 printf("id = %d 的进程正常终止,返回值是 %d\n", 17 child_pid, WEXITSTATUS(state)); 18 } 19 } 20 int main(int argc, char **argv) 21 { 22 int ser_sock, cli_sock; 23 char s[200]; 24 sockaddr_in ser_addr, cli_addr; 25 struct sigaction act; 26 act.sa_handler = child_over; 27 sigemptyset(&act.sa_mask); 28 act.sa_flags = 0; 29 sigaction(SIGCHLD, &act, 0);//信号注册函数 30 31 ser_sock = socket(PF_INET, SOCK_STREAM, 0); 32 33 int opt = 1; 34 setsockopt(ser_sock, SOL_SOCKET, SO_REUSEADDR, &opt, 4);//端口地址再分配 35 36 memset(&ser_addr, 0, sizeof(ser_addr)); 37 ser_addr.sin_family = AF_INET; 38 ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); 39 ser_addr.sin_port = htons(atoi(argv[1])); 40 41 if(bind(ser_sock, (sockaddr *)&ser_addr, sizeof(ser_addr)) != 0) 42 puts("bind error"); 43 if(listen(ser_sock, 5) != 0) 44 puts("listen error"); 45 46 while(1) 47 { 48 socklen_t s_len = sizeof(cli_addr); 49 cli_sock = accept(ser_sock, (sockaddr *)&cli_addr, &s_len); 50 if(cli_sock == -1) continue; 51 52 pid_t pid = fork(); 53 if(pid == 0) 54 { 55 close(ser_sock); 56 int len; 57 while(len = read(cli_sock, s, 100)) 58 { 59 if(!len) break; 60 s[len] = 0; 61 printf("message from client : %s\n", s); 62 write(cli_sock, s, len); 63 } 64 close(cli_sock); 65 return 3; 66 } 67 else 68 close(cli_sock); 69 } 70 close(ser_sock); 71 return 0; 72 }
I/O分割的回声客户端
1 #include <stdio.h> 2 #include <arpa/inet.h> 3 #include <cstring> 4 #include <cstdlib> 5 #include <unistd.h> 6 using namespace std; 7 int main(int argc, char **argv) 8 { 9 int sock; 10 sockaddr_in ser_addr; 11 char s[200]; 12 sock = socket(PF_INET, SOCK_STREAM, 0); 13 if(sock == -1) puts("socket error"); 14 memset(&ser_addr, 0, sizeof(ser_addr)); 15 ser_addr.sin_family = AF_INET; 16 ser_addr.sin_addr.s_addr = inet_addr(argv[1]); 17 ser_addr.sin_port = htons(atoi(argv[2])); 18 if(connect(sock, (sockaddr *)&ser_addr, sizeof(ser_addr)) == -1) 19 puts("connect error"); 20 21 22 pid_t pid = fork(); 23 if(pid == 0) 24 { 25 while(1) 26 { 27 puts("wait for message..."); 28 scanf("%s", s); 29 if(!strcmp(s, "q") || !strcmp(s, "Q")) 30 { 31 shutdown(sock, 1); 32 break; 33 } 34 else 35 write(sock, s, strlen(s)); 36 sleep(0.5); 37 } 38 } 39 else 40 { 41 while(1) 42 { 43 int len = read(sock, s, 100); 44 if(len == 0) break; 45 s[len] = 0; 46 printf("message from server:%s\n", s); 47 } 48 } 49 close(sock); 50 return 0; 51 }
客户端31行用shutdown而不用close的原因是:
注意:
1.如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
2.在多进程中如果一个进程中shutdown(sfd, SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会影响到其它进程.
3.shutdown,不考虑描述符的参考数,可选择中止一个方向的连接, 但是仅仅是断开连接,仍然需要close释放链接占用的文件描述符。