(六)多进程实现TCP服务端

首先,为什么要用多进程处理,多进程的好处是可靠性高,而且在处理大量数据的时候,多进程的速度会比多线程快,所有多进程还是要掌握的。

在一些实际项目中,进程和线程要根据实际场景用。

但是多进程是不能共享进程空间的,所以有很多变量都不能共享。除了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);
	}

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值