并发服务器端
#include <unistd.h> #include <stdio.h> #include <sys/wait.h> #include <cstring> #include <arpa/inet.h> #include <signal.h> #include <cstdlib> #include <iostream> using namespace std; void child_over(int sig)//信号处理器 { int state; int child_pid = waitpid(-1, &state, WNOHANG); if(WIFEXITED(state)) { printf("id = %d 的进程正常终止,返回值是 %d\n", child_pid, WEXITSTATUS(state)); } } int main(int argc, char **argv) { int ser_sock, cli_sock; char s[200]; sockaddr_in ser_addr, cli_addr; struct sigaction act; act.sa_handler = child_over; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGCHLD, &act, 0);//信号注册函数 ser_sock = socket(PF_INET, SOCK_STREAM, 0); int opt = 1; setsockopt(ser_sock, SOL_SOCKET, SO_REUSEADDR, &opt, 4);//端口地址再分配 memset(&ser_addr, 0, sizeof(ser_addr)); ser_addr.sin_family = AF_INET; ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); ser_addr.sin_port = htons(atoi(argv[1])); if(bind(ser_sock, (sockaddr *)&ser_addr, sizeof(ser_addr)) != 0) puts("bind error"); if(listen(ser_sock, 5) != 0) puts("listen error"); while(1) { socklen_t s_len = sizeof(cli_addr); cli_sock = accept(ser_sock, (sockaddr *)&cli_addr, &s_len); if(cli_sock == -1) continue; pid_t pid = fork(); if(pid == 0) { close(ser_sock); int len; while(len = read(cli_sock, s, 100)) { if(!len) break; s[len] = 0; printf("message from client : %s\n", s); write(cli_sock, s, len); } close(cli_sock); return 3; } else close(cli_sock); } close(ser_sock); return 0; }
I/O分割的回声客户端
#include <stdio.h> #include <arpa/inet.h> #include <cstring> #include <cstdlib> #include <unistd.h> using namespace std; int main(int argc, char **argv) { int sock; sockaddr_in ser_addr; char s[200]; sock = socket(PF_INET, SOCK_STREAM, 0); if(sock == -1) puts("socket error"); memset(&ser_addr, 0, sizeof(ser_addr)); ser_addr.sin_family = AF_INET; ser_addr.sin_addr.s_addr = inet_addr(argv[1]); ser_addr.sin_port = htons(atoi(argv[2])); if(connect(sock, (sockaddr *)&ser_addr, sizeof(ser_addr)) == -1) puts("connect error"); pid_t pid = fork(); if(pid == 0) { while(1) { puts("wait for message..."); scanf("%s", s); if(!strcmp(s, "q") || !strcmp(s, "Q")) { shutdown(sock, 1); break; } else write(sock, s, strlen(s)); sleep(0.5); } } else { while(1) { int len = read(sock, s, 100); if(len == 0) break; s[len] = 0; printf("message from server:%s\n", s); } } close(sock); return 0; }
客户端31行用shutdown而不用close的原因是:
注意:
1.如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
2.在多进程中如果一个进程中shutdown(sfd, SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会影响到其它进程.
3.shutdown,不考虑描述符的参考数,可选择中止一个方向的连接, 但是仅仅是断开连接,仍然需要close释放链接占用的文件描述符。