Linux 网络编程 全解(四)--------多进程并发服务器和多线程并发服务器

写在前面:这个系列也是停滞了20多天了,从今天开始再次步入正轨,以后每个周末都会陆陆续续的更新,这个系列预计完结的时间还会在大约一个月左右,今天静下心来多整理几篇。QQ:993650814

Linux 网络编程 全解(一)--------网络基础协议

Linux 网络编程 全解(二)--------套接字socket

Linux 网络编程 全解(三)--------TCP三次握手、数据传输、四次挥手、滑动窗口

正文:

一、多进程并发服务器

    设计思路:当有新的客户端连接到服务器时,服务器会调用accept函数与客户端建立连接,并创建子进程与连接上来的客户端进行通信。

    代码如下:

#include "stdio.h"
#include         
#include 
#include 
#include 
#include 
#include 
 #include 

#define SER_PORT (9999)

void do_sigchild(int param)
{
	printf("%s\n",__FUNCTION__);
	while(waitpid(0,NULL,WNOHANG)>0);
	
}

int main(void)
{
	int lfd = -1;
	int cfd = -1;
	struct sockaddr_in ser_addr;
	struct sockaddr_in cli_addr;
	pid_t pid = -1;
	char buf[1024] = {0x0};
	int read_size = 0;
	struct sigaction newact;
	
	
	lfd = socket(AF_INET, SOCK_STREAM, 0);
	
	memset(&ser_addr,0,sizeof(struct sockaddr_in));
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_port = htons(SER_PORT);
	ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	bind(lfd,(struct sockaddr *)&ser_addr,sizeof(ser_addr));
	
	memset(&newact,0,sizeof(struct sigaction));
	newact.sa_handler = do_sigchild;
	newact.sa_flags = 0;
	sigemptyset(&newact.sa_mask);
	
	//避免出现僵尸进程的情况:指定父进程回收子进程
	//sigaction(SIGCHLD, &newact,NULL);
	
	listen(lfd, 128);

	while(1)
	{
		socklen_t cli_addr_len = sizeof(cli_addr);
		cfd = accept(lfd, (struct sockaddr *)&cli_addr, &cli_addr_len);
		
		printf("client connect server\n");

		pid = fork();
		
		if(0 == pid)
		{
			//子进程
			close(lfd);
			while(1)
			{
				read_size = read(cfd, buf, sizeof(buf));
				if(read_size == 0)
				{
					printf("client has been closed\n");
					
					break;
				}
				printf("read content:%s\n",buf);
				
				memset(buf,0,sizeof(buf));
				
			}	
			
			printf("child pcb return \n");
			close(cfd);
			
			return 0;		
			
		}else if(pid > 0)
		{
			//父进程
			close(cfd);
			
			continue;
			
			
		}else
		{
			printf("fork error\n");
			
		}
		
		
		
	}
	
	
	close(lfd);
	
	return 0;
}


  测试结果:

Linux 网络编程 全解(四)--------多进程并发服务器和多线程并发服务器_第1张图片

二、多线程并发服务器

    设计思路:多线程服务器跟多进程服务器的思路其实一样,当有client发生连接时,服务器会调用accept跟client发生连接,并创建子线程来跟client通信。

    代码如下:

    

#include "stdio.h"
#include           
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define SERVER_PORT (8888)
typedef struct
{
	struct sockaddr_in cli_addr;
	int cfd;
}cliInfo_t;



void *task(void * arg)
{
	cliInfo_t * pCliInfo = (cliInfo_t *)arg;
	char ipAddr[10] = {0};
	int cli_port = 0;
	int read_size = 0;
	char buf[1024] = {0};
	
	inet_ntop(AF_INET, &(pCliInfo ->cli_addr.sin_addr), ipAddr, sizeof(ipAddr));
	printf("client ip addr : %s\n",ipAddr);
	
	cli_port =  ntohs(pCliInfo ->cli_addr.sin_port);
	printf("client port : %d\n",cli_port);

	//子线程分离,防止产生僵尸线程
	pthread_detach(pthread_self());
	
	while(1)
	{
		read_size = read(pCliInfo ->cfd, buf, sizeof(buf));
		
		if(read_size == 0)
		{
			printf("client closed\n");
			
			break;
		}
		
		printf("receive data from client:%s",buf);
		
		memset(buf,0,sizeof(buf));
	}
	
	close(pCliInfo ->cfd);
	
	return NULL;
}


int main(void)
{
	int lfd = -1;
	int cfd = -1;
	struct sockaddr_in ser_sock_addr, cli_sock_addr;
	socklen_t cli_addr_len = sizeof(cli_sock_addr);
	pthread_t tid;
	cliInfo_t cliInfo[100];
	int i = 0;
	int ret = -1;
	
	lfd = socket(AF_INET,SOCK_STREAM,0);
	
	ser_sock_addr.sin_family = AF_INET;
	ser_sock_addr.sin_port = htons(SERVER_PORT);
	ser_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	ret = bind(lfd,  (struct sockaddr *)&ser_sock_addr,sizeof(ser_sock_addr));
	if(ret < 0)
	{
		printf("bind error \n");
		
		return -1;
	}

	listen(lfd, 30);
	
	while(1)
	{
		cfd = accept(lfd, (struct sockaddr *)&cli_sock_addr, &cli_addr_len);
		
		cliInfo[i].cli_addr = cli_sock_addr;
		cliInfo[i].cfd = cfd;
		
		//当有客户端跟服务器发生连接时,创建子线程跟客户端数据通信
	    pthread_create(&tid, NULL,task, (void *)&cliInfo[i]);
		
		i++;
		
	}

	
	return 0;
}



 测试结果:

 现象其实跟多进程服务器的现象是一样的。

Linux 网络编程 全解(四)--------多进程并发服务器和多线程并发服务器_第2张图片

你可能感兴趣的:(Linux网络编程)