首先,为什么要用多进程处理,多进程的好处是可靠性高,而且在处理大量数据的时候,多进程的速度会比多线程快,所有多进程还是要掌握的。
在一些实际项目中,进程和线程要根据实际场景用。
但是多进程是不能共享进程空间的,所以有很多变量都不能共享。除了fork()之前的变量是可以共享的。
下面的代码基本逻辑就是,用父进程来 accept,检测有没有新的客户端要连入,用子进程来接受客户端发来的信息
下面给出服务端的代码:(有详细注释)
#include"myhead.h"
char rbuf[50];
char wbuf[50];
char ipbuf[50];
int main()
{
signal(SIGCHLD,SIG_IGN);//把子进程的僵尸进程给init进程处理
struct sockaddr_in saddr;
struct sockaddr_in caddr;
int size,len,opt = 1;
int sockfd,newfd;
pid_t pid;
int err;
size = sizeof(struct sockaddr_in);
len = sizeof(struct sockaddr);
//初始化本地ip,地址信息
bzero(&saddr,size);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8888);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
//创建一个监听套接字
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("failed socket");
return -1;
}
//设置端口复用
err = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
if(err<0)
{
perror("setsockopt failed");
return -1;
}
//绑定套接字和IP,地址信息
err = bind(sockfd,(struct sockaddr*)&saddr,len);
if(err<0)
{
perror("failed bind");
return -1;
}
//开始监听
listen(sockfd,10);
//循环接收 客户端的连入
while(1)
{
//监测有没有新的客户端连入,有的话,返回新的套接字
newfd = accept(sockfd,(struct sockaddr*)&caddr,&len);
if(newfd<0)
{
perror("accept failed");
continue;
}
//有新的客户端连入,则打印他的IP和端口
inet_ntop(AF_INET,(void*)&caddr.sin_addr.s_addr,
ipbuf,50);
printf("the client:%s is in\n",
ipbuf);
//创建一个子进程来接受新客户端的信息
pid = fork();
if(pid<0) //fork失败
{
perror("failed fork()");
return -1;
}
else if(pid == 0) //子进程
{
close(sockfd);//关闭从父进程进程来的监听套接字
//因为在子进程用不到
/*关闭不需要的套接字可节省系统资源,
同时可避免父子进程共享这些套接字
可能带来的不可预计的后果
*/
//这个子进程循环接收客户端信息
while(1)
{
err = recv(newfd,rbuf,50,0);
if(err<0)
{
perror("failed recv");
}
//若recv的返回=0,表示客户端已经断开
else if(err == 0)
{
bzero(ipbuf,50);
inet_ntop(AF_INET,(void*)&caddr.sin_addr.s_addr,
ipbuf,50);
printf("the client:%s is out\n",
ipbuf);
exit(0);
close(newfd);
}
//读取客户端的信息
else
{
inet_ntop(AF_INET,(void*)&caddr.sin_addr.s_addr,
ipbuf,50);
printf("ip:%s,port:%d\n",ipbuf,ntohs(caddr.sin_port));
printf("%s\n",rbuf);
bzero(rbuf,50);
}
}
}
else if(pid>0) //父进程,用于继续监测有没有新的客户端连入
{
close(newfd);//关闭新客户端返回的套接字,因为在
//父进程中用不到
continue;
}
}
}
再给出客户端的代码:
客户端的没啥好说的,通用的客户端代码就可以
#include "myhead.h"
char wbuf[50];
int main()
{
struct sockaddr_in saddr;
struct sockaddr_in caddr;
int size,len,opt = 1;
int sockfd,newfd;
pid_t pid;
int err;
size = sizeof(struct sockaddr_in);
len = sizeof(struct sockaddr);
bzero(&saddr,size);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8888);
saddr.sin_addr.s_addr = inet_addr("192.168.106.128");
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("failed socket");
return -1;
}
err = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
if(err<0)
{
perror("setsockopt failed");
return -1;
}
err = connect(sockfd,(struct sockaddr*)&saddr,
sizeof(struct sockaddr));
if(err<0)
{
perror("failed connect");
return -1;
}
while(1)
{
scanf("%s",wbuf);
write(sockfd,wbuf,50);
bzero(wbuf,50);
}
}