刚做的网站上线后收不到了,制作网页的软件都有哪些,绍兴网站制作建设,手机自己制作表白网站app文章目录 4.20 多进程实现并发服务器server_process.cclient.c4.22 多线程实现并发服务器客户端代码#xff1a;服务端代码#xff1a; 4.20 多进程实现并发服务器
要实现TCP通信服务器处理并发的任务#xff0c;使用多线程或者多进程来解决。 思路#xff1a; 1、一个父进… 文章目录 4.20 多进程实现并发服务器server_process.cclient.c4.22 多线程实现并发服务器客户端代码服务端代码 4.20 多进程实现并发服务器
要实现TCP通信服务器处理并发的任务使用多线程或者多进程来解决。 思路 1、一个父进程多个子进程 2、父进程负责等待并接受客户端的连接 3、子进程完成通信接受一个客户端连接就创建一个子进程用于通信
server_process.c
#include stdio.h
#include arpa/inet.h
#include unistd.h
#include stdlib.h
#include string.h
#include signal.h
#include wait.h
#include errno.hvoid recyleChild(int arg) {while(1) {int ret waitpid(-1, NULL, WNOHANG);if(ret -1) {// 所有的子进程都回收了break;}else if(ret 0) {// 还有子进程活着break;} else if(ret 0){// 被回收了printf(子进程 %d 被回收了\n, ret);}}
}int main() {//不能通过父进程进行子进程的回收使用信号的方式进程子进程的回收//子进程结束时会发送SIGCHILDstruct sigaction act;act.sa_flags 0;sigemptyset(act.sa_mask);//临时阻塞的信号集信号掩码清空act.sa_handler recyleChild;// 注册信号捕捉sigaction(SIGCHLD, act, NULL);// 创建socketint lfd socket(PF_INET, SOCK_STREAM, 0);if(lfd -1){perror(socket);exit(-1);}struct sockaddr_in saddr;saddr.sin_family AF_INET;saddr.sin_port htons(9999);saddr.sin_addr.s_addr INADDR_ANY;//0.0.0.0 ip地址// 绑定int ret bind(lfd,(struct sockaddr *)saddr, sizeof(saddr));if(ret -1) {perror(bind);exit(-1);}// 监听ret listen(lfd, 128);if(ret -1) {perror(listen);exit(-1);}// 不断循环等待客户端连接while(1) {struct sockaddr_in cliaddr;int len sizeof(cliaddr);// 接受连接int cfd accept(lfd, (struct sockaddr*)cliaddr, len);if(cfd -1) {//子进程结束回收子进程软中断再回到accept会产生EINTR错误若直接结束父进程后续客户端将无法连接到服务端if(errno EINTR) {continue;}perror(accept);exit(-1);}// 每一个连接进来创建一个子进程跟客户端通信pid_t pid fork();if(pid 0) {// 子进程// 获取客户端的信息char cliIp[16];inet_ntop(AF_INET, cliaddr.sin_addr.s_addr, cliIp, sizeof(cliIp));unsigned short cliPort ntohs(cliaddr.sin_port);printf(client ip is : %s, prot is %d\n, cliIp, cliPort);// 接收客户端发来的数据char recvBuf[1024];while(1) {int len read(cfd, recvBuf, sizeof(recvBuf));if(len -1) {perror(read);exit(-1);}else if(len 0) {printf(recv client : %s\n, recvBuf);} else if(len 0) {printf(client closed....\n);break;}write(cfd, recvBuf, strlen(recvBuf) 1);//回写回去,1将\0也放进去}close(cfd);exit(0); // 退出当前子进程}}close(lfd);return 0;
} int cfd accept(lfd, (struct sockaddr*)cliaddr, len);if(cfd -1) {//在系统调用获取到有效连接之前被信号打断。也就是accept本来阻塞着程序中断去处理回收子进程。//再回来以后accept就会产生一个EINTR错误。此时cfd -1 ,会被判断为有误直接exit直接结束父进程后续客户端将无法连接到服务端//所以这里需要加一个判断if(errno EINTR) {continue;}perror(accept);exit(-1);}client.c
// TCP通信的客户端
#include stdio.h
#include arpa/inet.h
#include unistd.h
#include string.h
#include stdlib.hint main() {// 1.创建套接字int fd socket(AF_INET, SOCK_STREAM, 0);if(fd -1) {perror(socket);exit(-1);}// 2.连接服务器端struct sockaddr_in serveraddr;serveraddr.sin_family AF_INET;inet_pton(AF_INET, 192.168.139.132, serveraddr.sin_addr.s_addr);serveraddr.sin_port htons(9999);int ret connect(fd, (struct sockaddr *)serveraddr, sizeof(serveraddr));if(ret -1) {perror(connect);exit(-1);}// 3. 通信char recvBuf[1024];int i 0;while(1) {sprintf(recvBuf, data : %d\n, i);// 给服务器端发送数据write(fd, recvBuf, strlen(recvBuf)1);int len read(fd, recvBuf, sizeof(recvBuf));if(len -1) {perror(read);exit(-1);} else if(len 0) {printf(recv server : %s\n, recvBuf);} else if(len 0) {// 表示服务器端断开连接printf(server closed...);break;}sleep(1);}// 关闭连接close(fd);return 0;
}
4.22 多线程实现并发服务器
客户端代码
// TCP通信的客户端
#include stdio.h
#include arpa/inet.h
#include unistd.h
#include string.h
#include stdlib.hint main() {// 1.创建套接字int fd socket(AF_INET, SOCK_STREAM, 0);if(fd -1) {perror(socket);exit(-1);}// 2.连接服务器端struct sockaddr_in serveraddr;serveraddr.sin_family AF_INET;inet_pton(AF_INET, 192.168.139.133, serveraddr.sin_addr.s_addr);serveraddr.sin_port htons(9999);int ret connect(fd, (struct sockaddr *)serveraddr, sizeof(serveraddr));if(ret -1) {perror(connect);exit(-1);}// 3. 通信char recvBuf[1024];int i 0;while(1) {sprintf(recvBuf, data : %d\n, i);// 给服务器端发送数据write(fd, recvBuf, strlen(recvBuf)1);int len read(fd, recvBuf, sizeof(recvBuf));if(len -1) {perror(read);exit(-1);} else if(len 0) {printf(recv server : %s\n, recvBuf);} else if(len 0) {// 表示服务器端断开连接printf(server closed...);break;}sleep(1);}// 关闭连接close(fd);return 0;
}
服务端代码
#include stdio.h
#include arpa/inet.h
#include unistd.h
#include stdlib.h
#include string.h
#include pthread.hstruct sockInfo {int fd; // 通信的文件描述符struct sockaddr_in addr;pthread_t tid; // 线程号
};struct sockInfo sockinfos[128];void * working(void * arg) {// 子线程和客户端通信 cfd 客户端的信息 线程号// 获取客户端的信息struct sockInfo * pinfo (struct sockInfo *)arg;char cliIp[16];inet_ntop(AF_INET, pinfo-addr.sin_addr.s_addr, cliIp, sizeof(cliIp));unsigned short cliPort ntohs(pinfo-addr.sin_port);printf(client ip is : %s, prot is %d\n, cliIp, cliPort);// 接收客户端发来的数据char recvBuf[1024];while(1) {int len read(pinfo-fd, recvBuf, sizeof(recvBuf));if(len -1) {perror(read);exit(-1);}else if(len 0) {printf(recv client : %s\n, recvBuf);} else if(len 0) {printf(client closed....\n);break;}write(pinfo-fd, recvBuf, strlen(recvBuf) 1);}close(pinfo-fd);return NULL;
}int main() {// 创建socketint lfd socket(PF_INET, SOCK_STREAM, 0);if(lfd -1){perror(socket);exit(-1);}struct sockaddr_in saddr;saddr.sin_family AF_INET;saddr.sin_port htons(9999);saddr.sin_addr.s_addr INADDR_ANY;// 绑定int ret bind(lfd,(struct sockaddr *)saddr, sizeof(saddr));if(ret -1) {perror(bind);exit(-1);}// 监听ret listen(lfd, 128);if(ret -1) {perror(listen);exit(-1);}// 初始化数据int max sizeof(sockinfos) / sizeof(sockinfos[0]);for(int i 0; i max; i) {bzero(sockinfos[i], sizeof(sockinfos[i]));sockinfos[i].fd -1;//表示该文件描述符可用sockinfos[i].tid -1;}// 循环等待客户端连接一旦一个客户端连接进来就创建一个子线程进行通信while(1) {struct sockaddr_in cliaddr;int len sizeof(cliaddr);// 接受连接int cfd accept(lfd, (struct sockaddr*)cliaddr, len);struct sockInfo * pinfo;for(int i 0; i max; i) {// 从这个数组中找到一个可以用的sockInfo元素if(sockinfos[i].fd -1) {pinfo sockinfos[i];break;}if(i max - 1) {sleep(1);i--;}}pinfo-fd cfd;memcpy(pinfo-addr, cliaddr, len);// 创建子线程pthread_create(pinfo-tid, NULL, working, pinfo);pthread_detach(pinfo-tid);}close(lfd);return 0;
}