目录
一、TCP编程
//用多进程的方式并发处理多个客户端
//代码
//运行结果:
二、会产生什么问题?(僵死进程)
三、如何解决?
//思路:
1.使用wait(),获取退出码
2.使用信号量:
//代码
//运行结果:
//逐步查看
编辑
//另一种方法
利用fork产生子进程,父进程只参与创建子进程,创建完成后,用子进程来接受数据,父进程关闭,直到最后数据接收完毕,子进程才关闭。
#include
#include
#include
#include
#include
#include
#include
#include
int socket_init();
void recv_data(int c)
{
while(1)
{
char buff[128]={0};
int n=recv(c,buff,127,0);
if(n<=0)//小于0,客户端关闭了,等于0失败了
{
break;
}
printf("buff=%s\n",buff);
send(c,"ok",2,0);
}
close(c);
printf("client close\n");
}
int main()
{
int sockfd=socket_init();
if(sockfd==-1)
{
exit(0);
}
while(1)
{
struct sockaddr_in caddr;
int len=sizeof(caddr);
int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
if(c<0)
{
continue;
}
pid_t pid=fork();
if(pid==-1)
{
close(c);
continue;
}
if(pid==0)
{
recv_data(c);
exit(0);
}
close(c);
}
}
int socket_init()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
return -1;
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);//网络字节 大端
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(res==-1)
{
printf("bind err\n");
return -1;
}
res=listen(sockfd,5);
{
if(res==-1)
{
return -1;
}
return sockfd;
}
}
~
//利用父进程fork产生的多个子进程可以处理多个客户端并发运行的问题
//有人连接,就会产生子进程,所以子进程会循环不断的产生,只要客户端一关闭,子进程就会退出,变成将死进程,所以将死进程也会不断的产生
// ps -ef |grep fork
f(pid==0)
{
recv_data(c);
exit(0);
}
close(c);//wait(NULL);//能解决将死进程问题,但是不能用,
//子进程还在接受数据,没有结束,wait就阻塞住了,
//就没有机会继续执行accept了
//就失去了并发特点了
signal(SIGCHLD,wait_child);
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int socket_init();
void recv_data(int c)
{
while(1)
{
char buff[128]={0};
int n=recv(c,buff,127,0);
if(n<=0)//小于0,客户端关闭了,等于0失败了
{
break;
}
printf("buff=%s\n",buff);
send(c,"ok",2,0);
}
close(c);
printf("client close\n");
}
void wait_child(int sig)
{
wait(NULL);
}
int main()
{
signal(SIGCHLD,wait_child);
int sockfd=socket_init();
if(sockfd==-1)
{
exit(0);
}
while(1)
{
struct sockaddr_in caddr;
int len=sizeof(caddr);
int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
if(c<0)
{
continue;
}
pid_t pid=fork();
if(pid==-1)
{
close(c);
continue;
}
if(pid==0)
{
recv_data(c);
exit(0);
}
close(c);
//wait(NULL);//能解决将死进程问题,但是不能用,子进程还在接受数据,没有结束,wait就阻塞住了,就没有机会继续执行accept了
//就失去了并发特点了
}
}
int socket_init()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
return -1;
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);//网络字节 大端
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(res==-1)
{
printf("bind err\n");
return -1;
}
res=listen(sockfd,5);
{
if(res==-1)
{
return -1;
}
return sockfd;
}
}
//第一次为执行服务器,运行两个客户端
//第二次为执行服务器,关闭一个客户端,只剩以一个客户端
//第三次为执行服务器,再关闭一个个客户端,无客户端,只剩服务器阻塞
//第四次强制退出服务器
将//signal(SIGCHLD,wait_child)
改为signal(SIGCHLD,SIG_IGN);
直接忽略信号,子进程结束后,直接把内核中的PCB移除,不看退出码