学会建设网站必要性,163免费邮箱入口,网站怎么获得流量,做软件的人叫什么文章目录 思路问题多进程并发回环服务器代码客户端代码 思路
每当一个客户端连接服务器后#xff0c;创建一个子进程负责与该客户端通信#xff0c;客户端断开连接之后#xff0c;服务器回收子进程资源。
问题 问题1#xff1a;父进程阻塞在等待连接(accept())处#xf… 文章目录 思路问题多进程并发回环服务器代码客户端代码 思路
每当一个客户端连接服务器后创建一个子进程负责与该客户端通信客户端断开连接之后服务器回收子进程资源。
问题 问题1父进程阻塞在等待连接(accept())处不能在父进程回收资源可以使用信号SIGCHLD进行软中断回调处理当子进程结束后会产生SIGCHLD信号信号触发回调函数进程子进程资源回收父进程阻塞在accept()函数时遇到软中断就会产生EINTR错误信号这就需要处理accept函数返回值为-1时的错误判断错误号errno若errno EINTR则继续等待客户端连接进入accept阻塞。 问题2由于多个进程同时退出时也仅有一个SIGCHLD信号所以在有SIGCHLD信号时回调函数内就要循环执行释放子进程资源直到子进程资源释放完成。 信号的注册以及回调函数的编写
//子进程回收回调函数
void recvChild(int arg)
{while(1){int ret waitpid(-1, NULL, WNOHANG);if(ret 0){printf(recv child, the num is:%d\n, ret);}else if(ret 0){//还有子进程}else if(ret -1){//没有子进程了break;}}
}//注册信号解决子进程的回收问题struct sigaction act;act.sa_flags 0;sigemptyset(act.sa_mask);act.sa_handler recvChild;sigaction(SIGCHLD, act, NULL);问题3在使用客户端发送数据的时候是先使用write发送数据然后通过read读取数据该读取是阻塞的所以一开始没有数据时是一直阻塞的回环服务器接收到数据回传给客户端这样客户端和服务器同时进行read时就会出现都阻塞的状态。 可以设置客户端先发送再读取客户端发送后数据经过服务器回传客户端收到数据后再进行下一次发送若有一次数据丢失则无法进行数据发送有一直阻塞在接收的风险。 也可以在客户端设置两个进程一个发送进程一个接收进程这样就可以解决。 问题4接收数据中没有结束符’\0’在printf %s时会导致数据错误数据先长后短打印的会包含上次数据注意结束符的位置strlen计算到结束符之前。 通过在接收的字符串后补上结束符处理 或者接收数据前对接收数组进行清空处理 ********////接收数据没有字符结束符无法判断数据结束//使用printf%s出现问题可以将末尾增加字符结束符/0,也可以使用数据初始化浪费资源
//memset(recv, 0, 1024);
int len read(cfd, recv, 1024);
recv[len] 0;多进程并发回环服务器代码
#include stdio.h
#include stdlib.h
#include arpa/inet.h
#include unistd.h
#include string.h
#include signal.h
#include wait.h
#include errno.hvoid recvChild(int arg)
{while(1){int ret waitpid(-1, NULL, WNOHANG);if(ret 0){printf(recv child, the num is:%d\n, ret);}else if(ret 0){//还有子进程}else if(ret -1){//没有子进程了break;}}
}int main()
{//注册信号解决子进程的回收问题struct sigaction act;act.sa_flags 0;sigemptyset(act.sa_mask);act.sa_handler recvChild;sigaction(SIGCHLD, act, NULL);//socketint lfd socket(PF_INET, SOCK_STREAM, 0);if(lfd -1){perror(socket);exit(-1);}//bindstruct sockaddr_in saddr;saddr.sin_family AF_INET;inet_pton(AF_INET, 192.168.1.108, saddr.sin_addr.s_addr);//saddr.sin_addr.s_addr INADDR_ANY;saddr.sin_port htons(9999);int ret bind(lfd, (struct sockaddr *)saddr, sizeof(saddr));if(ret -1){perror(bind);exit(-1);}//listenret listen(lfd, 2);if(ret -1){perror(listen);exit(-1);}int prosess_num 0;while(1){//acceptstruct sockaddr_in caddr;socklen_t len sizeof(caddr);int cfd accept(lfd, (struct sockaddr *)caddr, len);if(cfd -1){if(errno EINTR) continue;perror(accept);exit(-1);}//childprosess_num;pid_t fd fork();if(fd -1){perror(fork);exit(-1);}if(fd 0){char cip[16];printf(the process %d link success!\n, prosess_num);inet_ntop(AF_INET, caddr.sin_addr, cip, sizeof(cip));printf(client IP:%s, Port:%d\n\n, cip, ntohs(caddr.sin_port));char recv[1025];while(1){********//
//接收数据没有字符结束符无法判断数据结束
//使用printf%s出现问题可以将末尾增加字符结束符/0,也可以使用数据初始化浪费资源//memset(recv, 0, 1024);int len read(cfd, recv, 1024);recv[len] 0;if(len -1){perror(read);exit(-1);}else if(len 0){if(strcmp(recv, break\r\n) 0) break;write(cfd, recv, len1);printf(IP:%s Port:%d: %s, cip, ntohs(caddr.sin_port), recv);}else{printf(client is closed...\n);break;}}printf(the process %d, IP:%s, port:%d, will close!\n, prosess_num, cip, ntohs(caddr.sin_port));close(cfd);exit(0);}}close(lfd); return 0;
}客户端代码
#include stdio.h
#include stdlib.h
#include unistd.h
#include arpa/inet.h
#include string.h
#include fcntl.hint main()
{int lfd socket(PF_INET, SOCK_STREAM, 0);if(lfd -1){perror(socket);exit(-1);}struct sockaddr_in saddr;saddr.sin_family AF_INET;int len sizeof(saddr);inet_pton(AF_INET, 192.168.1.108, saddr.sin_addr.s_addr);saddr.sin_port htons(9999);int ret connect(lfd, (struct sockaddr *)saddr, sizeof(saddr));if(ret -1){perror(connect);exit(-1);}printf(client link success!\n);//由于读操作会阻塞客户端需要先发送数据若先读取数据一个进程就会阻塞住一个进程就要先发数据如果一次数据没有接收到则会阻塞住。//可以采用两个进程发、收互不影响pid_t pid fork();if(pid0){char rbuf[1024];while(1){//memset(rbuf, 0, 1024);int lent read(lfd, rbuf, 1024);if(lent 0){printf(send: %s, rbuf);}else if(lent -1) perror(read);}}else if(pid 0){int i 0;char sbuf[1024];while(1){ i;if(i 255) i 0;sprintf(sbuf, the num is %d\n, i);write(lfd, sbuf,strlen(sbuf));sleep(1);}}close(lfd);return 0;
}