免费建网站讨论,js网站下拉置顶代码,西柏坡旅游网站建设规划书,怎么做网站营销策划目录
1.可循环发送数据的代码
2.改成循环之后每次发现只能处理一个客户端
3.服务器端处理并发问题
3.1 思路
3.2 利用多线程实现并发
编辑
3.3 利用多进程实现并发
3.3.1 多进程并发产生的僵死进程问题
3.3.2 解决僵死进程问题 1.可循环发送数据的代码
服务器代…
目录
1.可循环发送数据的代码
2.改成循环之后每次发现只能处理一个客户端
3.服务器端处理并发问题
3.1 思路
3.2 利用多线程实现并发
编辑
3.3 利用多进程实现并发
3.3.1 多进程并发产生的僵死进程问题
3.3.2 解决僵死进程问题 1.可循环发送数据的代码
服务器代码
#include stdio.h
#include stdlib.h
#include assert.h
#include unistd.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
#include string.h
int main()
{int sockfdsocket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!-1);struct sockaddr_in saddr,caddr;memset(saddr,0,sizeof(saddr));saddr.sin_familyAF_INET;saddr.sin_porthtons(6000);//主机网络大小端转换saddr.sin_addr.s_addrinet_addr(127.0.0.1);//IP地址转换int resbind(sockfd,(struct sockaddr*)saddr,sizeof(saddr));assert(res!-1);reslisten(sockfd,5);assert(res!-1);while(1){int lensizeof(saddr);printf(accept wait...\n);int caccept(sockfd,(struct sockaddr*)caddr,len);//链接套接字if(c0){continue;}printf(accept c%d\n,c);printf(accept client ip:%s ,port%d\n,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));while(1){ char buff[128]{0};int nrecv(c,buff,127,0);//返回值为0说明断开连接if(n0){break;}printf(buff%s\n,buff);send(c,ok,2,0);}close(c);}close(sockfd);exit(0);
}客户端代码
#include stdio.h
#include stdlib.h
#include assert.h
#include unistd.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
#include string.h
int main()
{int sockfdsocket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!-1);struct sockaddr_in saddr;memset(saddr,0,sizeof(saddr));saddr.sin_familyAF_INET;saddr.sin_porthtons(6000);saddr.sin_addr.s_addrinet_addr(127.0.0.1);int resconnect(sockfd,(struct sockaddr*)saddr,sizeof(saddr));assert(res!-1);while(1){printf(input:\n);char buff[128]{0};fgets(buff,127,stdin);if(strncmp(buff,end,3)0){break;}send(sockfd,buff,strlen(buff),0);memset(buff,0,128);recv(sockfd,buff,127,0);printf(read:%s\n,buff);}close(sockfd);exit(0);
}运行结果 2.改成循环之后每次发现只能处理一个客户端
将代码从单词发送数据改为while(1)循环发送数据后我们发现每次只能处理一个客户端其它客户端消息无法发送给服务器。 原因 3.服务器端处理并发问题
3.1 思路
这个问题可以通过引入多线程和多进程来解决。
服务端接收一个客户端的连接后accept之后创建一个线程或者进程然后在新创建的线程或进程中循环处理数据。
主线程(父进程)只负责监听客户端的连接并使用 accept()接受连接,不进行数据的处理。如下图所示: 3.2 利用多线程实现并发
客户端代码不变服务器端代码做如下更改
#include stdio.h
#include stdlib.h
#include assert.h
#include unistd.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
#include string.h
#include pthread.h
void* work_pthread(void*arg)
{ int c*(int*)arg;while(1){char buff[128]{0};int nrecv(c,buff,127,0);//返回值为0说明断开连接if(n0){break;}printf(recv(%d)%s\n,c,buff);send(c,ok,2,0);}printf(one clinet over!\n);close(c);
}int main()
{int sockfdsocket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!-1);struct sockaddr_in saddr,caddr;memset(saddr,0,sizeof(saddr));saddr.sin_familyAF_INET;saddr.sin_porthtons(6000);//主机网络大小端转换saddr.sin_addr.s_addrinet_addr(127.0.0.1);//IP地址转换int resbind(sockfd,(struct sockaddr*)saddr,sizeof(saddr));assert(res!-1);reslisten(sockfd,5);assert(res!-1);while(1){int lensizeof(saddr);printf(accept wait...\n);int caccept(sockfd,(struct sockaddr*)caddr,len);//链接套接字if(c0){continue;}printf(accept c%d\n,c);printf(accept client ip:%s ,port%d\n,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));pthread_t id;pthread_create(id,NULL,work_pthread,(void*)c);}close(sockfd);exit(0);
}netstat -natp连接成功之后发现有两个./ser 3.3 利用多进程实现并发
客户端代码不变服务器代码如下
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include assert.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.hvoid DealClientLink(int c,struct sockaddr_in caddr)
{while(1){char buff[128]{0};int nrecv(c,buff,127,0);//返回值为0说明断开连接if(n0){break;}printf(%s:%d:buff%s\n,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buff);send(c,ok,2,0);}printf(one clinet unlike!\n);close(c);
}int main()
{int sockfdsocket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!-1);struct sockaddr_in saddr,caddr;memset(saddr,0,sizeof(saddr));saddr.sin_familyAF_INET;saddr.sin_porthtons(6000);//主机网络大小端转换saddr.sin_addr.s_addrinet_addr(127.0.0.1);//IP地址转换int resbind(sockfd,(struct sockaddr*)saddr,sizeof(saddr));assert(res!-1);reslisten(sockfd,5);assert(res!-1);printf(%s:%d link success!\n,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));while(1){int lensizeof(saddr);int caccept(sockfd,(struct sockaddr*)caddr,len);//链接套接字if(c0){continue;}pid_t pidfork();assert(pid!-1);if(pid0){DealClientLink(c,caddr);exit(0);}}close(sockfd);exit(0);
}运行结果 3.3.1 多进程并发产生的僵死进程问题
子进程为客户端父进程为服务器端子进程先于父进程结束父进程没有获取到子进程的退出码子进程就会变成僵死进程占用内存影响执行速度。
客户端代码运行前 关闭客户端子进程结束后
如下图产生了两个僵死进程。 3.3.2 解决僵死进程问题
修改一下代码让父进程调用wait()方法获取子进程的退出码并结合信号使用让它不再阻塞。
#include wait.hvoid fun(int sig)
{wait(sig);
}signal(SIGCHLD,fun);//在主进程中添加
完整代码
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include assert.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
#include wait.hvoid DealClientLink(int c,struct sockaddr_in caddr)
{while(1){char buff[128]{0};int nrecv(c,buff,127,0);//返回值为0说明断开连接if(n0){break;}printf(%s:%d:buff%s\n,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buff);send(c,ok,2,0);}printf(one clinet unlike!\n);close(c);
}void fun(int sign)
{wait(sign);
}int main()
{signal(SIGCHLD,fun);int sockfdsocket(AF_INET,SOCK_STREAM,0);//监听套接字assert(sockfd!-1);struct sockaddr_in saddr,caddr;memset(saddr,0,sizeof(saddr));saddr.sin_familyAF_INET;saddr.sin_porthtons(6000);//主机网络大小端转换saddr.sin_addr.s_addrinet_addr(127.0.0.1);//IP地址转换int resbind(sockfd,(struct sockaddr*)saddr,sizeof(saddr));assert(res!-1);reslisten(sockfd,5);assert(res!-1);printf(%s:%d link success!\n,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));while(1){int lensizeof(saddr);int caccept(sockfd,(struct sockaddr*)caddr,len);//链接套接字if(c0){continue;}pid_t pidfork();assert(pid!-1);if(pid0){DealClientLink(c,caddr);exit(0);}}close(sockfd);exit(0);
}使用ps -f命令查看进程信息可以看到子进程退出后没有僵死进程。