linux——17服务器多客户端模型

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

一、多路io

1.select版本

	在TCP中已知tcp获取地址
	int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
	

a.服务器

#include "head.h"

int main(int argc, const char *argv[])
{
	int listen_fd = socket(AF_INET,SOCK_STREAM,0);	
	if(-1 == listen_fd)
	{
		perror("listen_fd error");
		return -1;
	}

	struct sockaddr_in ser,cli;

	ser.sin_family = AF_INET;
	ser.sin_port = htons(50000);
	ser.sin_addr.s_addr = inet_addr("192.168.0.180");

	int ret = bind(listen_fd,(SA)&ser,sizeof(ser));
	if(-1 == ret)
	{
		perror("bind error");
		return -1;
	}

	listen(listen_fd,3);
	int len = sizeof(cli);
	/*1.创建集合*/
	fd_set temp_fd; 
	fd_set rd_set;
	/*2.清空集合*/
	FD_ZERO(&temp_fd);
	FD_ZERO(&rd_set);
	/*3.将监听套接字放入temp_fd集合中*/
	FD_SET(listen_fd,&temp_fd);
	
	int maxfd = listen_fd;
	int i = 0;
	int conn;
	while(1)
	{
		/*5.清楚标志位*/
		rd_set = temp_fd;
		/*4.等待事件到来,监听套接字响应有客户端连接*/
		select(maxfd+1,&rd_set,NULL,NULL,NULL);
		/*i=listen_fd,不能从0开始*/
		for(i=listen_fd;i<maxfd+1;++i)
		{
			/*6.处理事件*/
			if(FD_ISSET(listen_fd,&rd_set) && i == listen_fd)
			{
				conn = accept(listen_fd,(SA)&cli,&len);
				/*有新的客户端连接进行,将套接字放入待检测的集合中*/
				FD_SET(conn,&temp_fd);
				/*如果套接字最大描述符大则更新最大描述符*/
				if(conn > maxfd)
				{
					maxfd = conn;
				}
			}
			if(FD_ISSET(i,&rd_set) && i != listen_fd)
			{
				char buf[1024] = {0};
				int ret_rd = recv(i,buf,sizeof(buf),0);
				if(ret_rd <= 0)
				{
					/*有客户端连接离开,将套接字从待检测的集合中移除*/
					FD_CLR(i,&temp_fd);
					close(i);
				}
				time_t tm;
				time(&tm);
				sprintf(buf,"%s : %s",buf,ctime(&tm));
				send(i,buf,strlen(buf),0);
			}
		}
	}
	close(conn);
	close(listen_fd);
	return 0;
}


b.客户端

#include "head.h"

int main(int argc, const char *argv[])
{
	int conn = socket(AF_INET,SOCK_STREAM,0);	
	if(-1 == conn)
	{
		perror("conn error");
		return -1;
	}

	struct sockaddr_in ser;

	ser.sin_family = AF_INET;
	ser.sin_port = htons(50000);
	ser.sin_addr.s_addr = inet_addr("192.168.0.180");

	connect(conn,(SA)&ser,sizeof(ser));

	while(1)
	{
		char buf[1024] = {"this is tcp test "};
		send(conn,buf,strlen(buf),0);

		int ret_rd = recv(conn,buf,sizeof(buf),0);
		if(ret_rd == -1)
		{
			break;
		}
		sleep(1);
		printf(buf,"%s\n",buf);
	}
	close(conn);


	return 0;
}

2.epoll版本

a.服务器

#include "head.h"

int add_ep(int ep_fd ,int fd)
{
	struct epoll_event ev;
	ev.data.fd = fd;
	ev.events = EPOLLIN ;
	int ret = epoll_ctl(ep_fd,EPOLL_CTL_ADD,fd,&ev);
	if(-1 == ret)
	{
		perror("epoll_ctl error");
		exit(1);
	}
	return 0;
}
int del_ep(int ep_fd,int fd)
{
	struct epoll_event ev;
	ev.data.fd = fd;
	ev.events = EPOLLIN ;
	int ret = epoll_ctl(ep_fd,EPOLL_CTL_DEL,fd,&ev);
	if(-1 == ret)
	{
		perror("epoll_ctl error");
		exit(1);
	}
	return 0;
}
int main(int argc, const char *argv[])
{
	int listen_fd = socket(AF_INET,SOCK_STREAM,0);	
	if(-1 == listen_fd)
	{
		perror("listen_fd error");
		return -1;
	}

	struct sockaddr_in ser,cli;

	ser.sin_family = AF_INET;
	ser.sin_port = htons(50000);
	ser.sin_addr.s_addr = inet_addr("192.168.0.180");

	int ret = bind(listen_fd,(SA)&ser,sizeof(ser));
	if(-1 == ret)
	{
		perror("bind error");
		return -1;
	}

	listen(listen_fd,3);
	int len = sizeof(cli);
	int conn ;

	time_t tm;
	/*1.创建事件结构体集合*/
	int ep_fd = epoll_create(100);
	/*2.向结合中添加关心的文件描述符*/
	add_ep(ep_fd,listen_fd);
	struct epoll_event rev[100];
	int i =0;
	while(1)
	{
		/*3.等待事件响应*/
		int ret_ep = epoll_wait(ep_fd,rev,100,-1);
		for(i=0;i<ret_ep;++i)
		{
			if(rev[i].data.fd == listen_fd)
			{
				conn = accept(listen_fd,(SA)&cli,&len);
				/*4.将新来的客户端,添加到集合中*/
				add_ep(ep_fd,conn);
			}
			if(rev[i].data.fd != listen_fd)
			{
				char buf[1024] = {0};
				int conn = rev[i].data.fd;
				int ret_rd = recv(conn,buf,sizeof(buf),0);
				if(ret_rd <= 0)
				{
					/*5.若客户端离开,则将文件描述符从集合中删除*/
					del_ep(ep_fd,conn);
					close(conn);
				}
				time(&tm);
				sprintf(buf,"%s : %s",buf,ctime(&tm));
				send(conn,buf,strlen(buf),0);
			}
		}
	}
	close(conn);
	close(listen_fd);
	return 0;
}

b.客户端

#include "head.h"

int main(int argc, const char *argv[])
{
	int conn = socket(AF_INET,SOCK_STREAM,0);	
	if(-1 == conn)
	{
		perror("conn error");
		return -1;
	}
	struct sockaddr_in ser;

	ser.sin_family = AF_INET;
	ser.sin_port = htons(50000);
	ser.sin_addr.s_addr = inet_addr("192.168.0.180");

	connect(conn,(SA)&ser,sizeof(ser));

	while(1)
	{
		char buf[1024] = {"this is tcp test "};
		send(conn,buf,strlen(buf),0);

		int ret_rd = recv(conn,buf,sizeof(buf),0);
		if(ret_rd == -1)
		{
			break;
		}
		sleep(1);
		printf(buf,"%s\n",buf);
	}
	close(conn);
	return 0;
}

3.进程版本

a.服务器

#include "head.h"
/*信号处理函数,回收子进程空间*/
void handle(int num)
{
	wait(NULL);
	return ;
}
int main(int argc, const char *argv[])
{
	signal(SIGCHLD,handle);
	int listen_fd = socket(AF_INET,SOCK_STREAM,0);	
	if(-1 == listen_fd)
	{
		perror("listen_fd error");
		return -1;
	}

	struct sockaddr_in ser,cli;

	ser.sin_family = AF_INET;
	ser.sin_port = htons(50000);
	ser.sin_addr.s_addr = inet_addr("192.168.0.180");

	int ret = bind(listen_fd,(SA)&ser,sizeof(ser));
	if(-1 == ret)
	{
		perror("bind error");
		return -1;
	}

	listen(listen_fd,3);
	int len = sizeof(cli);

	int conn;
	while(1)
	{
		conn = accept(listen_fd,(SA)&cli,&len);
		pid_t pid = fork();
		if(pid < 0)
		{
			perror("fork error ");
			return -1;
		}
		if(pid > 0 )
		{	
			/*父进程中conn不使用,且发生了复制,将conn关闭,如果不关闭文件描述符累计到1023*/
			close(conn);
		}
		else if(pid == 0)
		{
			/*子进程中不使用listen_fd,关闭监听套接字*/
			close(listen_fd);
			while(1)
			{
				char buf[1024] = {0};
				int ret_rd = recv(conn,buf,sizeof(buf),0);
				if(ret_rd <= 0)
				{
					close(conn);
					exit(1);
				}
				time_t tm;
				time(&tm);
				sprintf(buf,"%s : %s",buf,ctime(&tm));
				send(conn,buf,strlen(buf),0);
			}
		}
	}

	return 0;
}


b.客户端

#include "head.h"

int main(int argc, const char *argv[])
{
	int conn = socket(AF_INET,SOCK_STREAM,0);	
	if(-1 == conn)
	{
		perror("conn error");
		return -1;
	}

	struct sockaddr_in ser;

	ser.sin_family = AF_INET;
	ser.sin_port = htons(50000);
	ser.sin_addr.s_addr = inet_addr("192.168.0.180");

	connect(conn,(SA)&ser,sizeof(ser));

	while(1)
	{
		char buf[1024] = {"this is tcp test "};
		send(conn,buf,strlen(buf),0);

		int ret_rd = recv(conn,buf,sizeof(buf),0);
		if(ret_rd == -1)
		{
			break;
		}
		sleep(1);
		printf(buf,"%s\n",buf);
	}
	close(conn);


	return 0;
}

4.线程版本

a.服务器

#include "head.h"

void* thread(void *arg)
{
	pthread_detach(pthread_self());
	int conn = *(int*)arg;
	while(1)
	{
		char buf[1024] = {0};
		int ret_rd = recv(conn,buf,sizeof(buf),0);
		if(ret_rd <= 0)
		{
			close(conn);
			break;
		}
		time_t tm;
		time(&tm);
		sprintf(buf,"%s : %s",buf,ctime(&tm));
		send(conn,buf,strlen(buf),0);
	}
	return NULL;
}

int main(int argc, const char *argv[])
{

	int listen_fd = socket(AF_INET,SOCK_STREAM,0);	
	if(-1 == listen_fd)
	{
		perror("listen_fd error");
		return -1;
	}

	struct sockaddr_in ser,cli;

	ser.sin_family = AF_INET;
	ser.sin_port = htons(50000);
	ser.sin_addr.s_addr = inet_addr("192.168.0.180");

	int ret = bind(listen_fd,(SA)&ser,sizeof(ser));
	if(-1 == ret)
	{
		perror("bind error");
		return -1;
	}
	
	listen(listen_fd,3);
	int len = sizeof(cli);
	int conn ;

	while(1)
	{
		conn = accept(listen_fd,(SA)&cli,&len);
		pthread_t tid ;
		pthread_create(&tid,NULL,thread,&conn);

	}
	close(listen_fd);


	return 0;
}

b.客户端

#include "head.h"

int main(int argc, const char *argv[])
{
	int conn = socket(AF_INET,SOCK_STREAM,0);	
	if(-1 == conn)
	{
		perror("conn error");
		return -1;
	}

	struct sockaddr_in ser;

	ser.sin_family = AF_INET;
	ser.sin_port = htons(50000);
	ser.sin_addr.s_addr = inet_addr("192.168.0.180");

	connect(conn,(SA)&ser,sizeof(ser));

	while(1)
	{
		char buf[1024] = {"this is tcp test "};
		send(conn,buf,strlen(buf),0);

		int ret_rd = recv(conn,buf,sizeof(buf),0);
		if(ret_rd == -1)
		{
			break;
		}
		sleep(1);
		printf(buf,"%s\n",buf);
	}
	close(conn);


	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值