网络编程并发服务器的应用

作业2:完成局域网CS模型,局域网内一个服务器,多个客户端连接一个服务器,完成局域网聊天(select函数,poll函数,完成TCP并发服务器)。

poll函数应用:

服务器部分代码:

cs 复制代码
//TCP服务器
#include<myhead.h> 
#include<poll.h>
#define IP "192.168.60.68"
#define PORT 1028
#define BACKLOG 20
int main(int argc, const char *argv[])
{
	//AF_INET:IPv4通信
	int oldfd=socket(AF_INET,SOCK_STREAM,0);
	if(oldfd==-1)
	{
		perror("socket");
		return -1;
	}
	int n=1;
	int res=setsockopt(oldfd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(n));
	if(res==0)
	{
		printf("端口号快速复用成功\n");
	}
	//2、绑定IP和端口号
	struct sockaddr_in server={
	.sin_family=AF_INET,//IPv4
	.sin_port=htons(PORT),//端口号转为网络字节序
	.sin_addr.s_addr=inet_addr(IP),//IP地址
	};
	
	if(bind(oldfd,(struct sockaddr *)&server,sizeof(server))==-1)
	{
		perror("bind");
		return -1;
	}
	//3、监听
	if(listen(oldfd,BACKLOG)==-1)
	{
		perror("listen");
		return -1;
	}
	//4、接受客户端连接请求创建新的描述符用于通信
	//1-1设置结构体数组检测描述符发生事件
	struct pollfd fds[100];
	fds[0].fd=oldfd;//旧的套接字描述符检测数组中
	fds[0].events=POLLIN;
	int i;
	struct sockaddr_in client;
	socklen_t client_len=sizeof(client);
	int newfd;
	int count=1;
	while(1)
	{
		int res=poll(fds,100,-1);
		if(res==-1)
		{
			perror("poll");
		}
		if(res==0)
		{
			printf("超时\n");
		}
		if(fds[0].revents==POLLIN)
		{
			newfd=accept(oldfd,(struct sockaddr *)&client,&client_len);
			if(newfd==-1)
			{
				perror("accept");
				return -1;
			}
				printf("%s发来连接请求\n",inet_ntoa(client.sin_addr));
			fds[count].fd=newfd;
			fds[count++].events=POLLIN;
		}
		for(i=1;i<100;i++)
		{
			if(fds[i].fd>0&&fds[i].revents==POLLIN)
			{
				char buff[1024];
				memset(buff,0,sizeof(buff));
				int len=recv(fds[i].fd,buff,sizeof(buff),0);
				if(len==0)
				{
					printf("客户端下线\n");
					close(fds[i].fd);
					break;
				}
				printf("%s\n",buff);
				strcat(buff,"今天是周一");
				send(fds[i].fd,buff,sizeof(buff),0);
			}
		}
	}
	close(oldfd);
	return 0;
}

客户端代码部分:

cs 复制代码
//TCP客户端
#include<myhead.h> 
#define  IP "192.168.60.68"
#define PORT  1028
int main(int argc, const char *argv[])
{
	//1、创建套接字
	int oldfd=socket(AF_INET,SOCK_STREAM,0);
	if(oldfd==-1)
	{
		perror("socket");
		return -1;
	}

	struct sockaddr_in server={
	.sin_family=AF_INET,
	.sin_port = htons(PORT),
	.sin_addr.s_addr =inet_addr(IP),
	};

	if(connect(oldfd,(struct sockaddr *)&server,sizeof(server))==-1)
	{
		perror("connect");
		return -1;
	}

	char buff[1024];
	while(1)
	{
		fgets(buff,sizeof(buff),stdin);
		send(oldfd,buff,sizeof(buff),0);
		int len=recv(oldfd,buff,sizeof(buff),0);
		if(len==0)
		{
			perror("服务意外退出\n");
			break;
		}
		printf("接受服务器消息:%s\n",buff);
	}
	close(oldfd);
	return 0;
}

效果演示:

selsect函数部分:

代码效果:

服务器部分:

cs 复制代码
#include <myhead.h>
#define IP "192.168.60.68"
#define PORT 1028
#define BACKLOG 20

int main(int argc, const char *argv[])
{
	//AF_INET:IPV4通信
	//SOCK_STREAM:TCP通信协议
	int oldfd = socket(AF_INET,SOCK_STREAM,0);//1、创建套接字
	if(oldfd==-1)
	{
		perror("socket");
		return -1;
	}
	
	//2、绑定IP和端口号
	struct sockaddr_in server = {
	.sin_family = AF_INET,//IPV4
	.sin_port = htons(PORT),//端口号转为网络字节序
	.sin_addr.s_addr = inet_addr(IP),//IP地址
	};
	if(bind(oldfd,(struct sockaddr *)&server,sizeof(server))==-1)
	{
		perror("bind");
		return -1;
	}
	
	//3、监听
	if(listen(oldfd,BACKLOG)==-1)
	{
		perror("listen");
		return -1;
	}
	//4、接受客户端连接请求创建新的描述符用于通信
	struct sockaddr_in client;//接收客户端信息的结构体
	socklen_t client_len = sizeof(client);//计算出结构体大小
	//1-1定义容器放入描述符
	fd_set readfds,temp;//定义两个集合存放描述符
	FD_ZERO(&readfds);//清空集合内的内容
	FD_SET(0,&readfds);
	FD_SET(oldfd,&readfds);//描述符放入集合
	int maxfd = oldfd;//保留最大的描述符

	int newfd;
	
	while(1)//循环连入多个客户端
	{
		
		//1-2监视所有的描述符
		temp = readfds;
		int res = select(maxfd+1,&temp,NULL,NULL,NULL);//永久阻塞
		if(res==-1)
		{
			perror("select");
			return -1;
		}
		if(res==0)
		{
			printf("超时\n");
			continue;
		}
		//程序执行到此,说明某些描述符解除了阻塞	
		//1-3循环检测是谁发生了IO操作 
		int i;
		for(i = 0;i<=maxfd;i++)
		{
			if(!FD_ISSET(i,&temp))//如果描述符不在容器中,继续下次循环查找
			{
				continue;
			}
			if(i==oldfd)//旧的描述符解除的阻塞
			{
				newfd = accept(i,(struct sockaddr *)&client,&client_len);
				FD_SET(newfd,&readfds);//产生新描述符代表新客户端,需要放入集合
				maxfd = newfd>maxfd?newfd:maxfd;//更新最大的描述符
				if(newfd==-1)
				{
					perror("accept");
					return -1;
				}
				printf("%s发来连接请求\n",inet_ntoa(client.sin_addr));
			}	
			else//0号描述符解除的阻塞,进行通话
			{
				//5、循环收发信息
				char buff[1024];
				memset(buff,0,sizeof(buff));
				int len = recv(i,buff,sizeof(buff),0);//0:阻塞发送 MSG_DONTWAIT:非阻塞
				if(len==0)
				{
					close(i);//关闭新的描述符
					FD_CLR(i,&readfds);//移除退出的客户端描述符
					if(maxfd==i)//退出后,描述符个数减一
					{
						maxfd--;
					}
					printf("客户端下线\n");
					break;
				}
				printf("%s\n",buff);
				fgets(buff,sizeof(buff),stdin);
				send(i,buff,sizeof(buff),0);
			}
		}
	}
	close(oldfd);
	return 0;
}

客户端部分:

cs 复制代码
//TCP客户端
#include<myhead.h> 
#define  IP "192.168.60.68"
#define PORT  1028
int main(int argc, const char *argv[])
{
	//1、创建套接字
	int oldfd=socket(AF_INET,SOCK_STREAM,0);
	if(oldfd==-1)
	{
		perror("socket");
		return -1;
	}

	struct sockaddr_in server={
	.sin_family=AF_INET,
	.sin_port = htons(PORT),
	.sin_addr.s_addr =inet_addr(IP),
	};

	if(connect(oldfd,(struct sockaddr *)&server,sizeof(server))==-1)
	{
		perror("connect");
		return -1;
	}

	char buff[1024];
	while(1)
	{
		fgets(buff,sizeof(buff),stdin);
		send(oldfd,buff,sizeof(buff),0);
		int len=recv(oldfd,buff,sizeof(buff),0);
		if(len==0)
		{
			perror("服务意外退出\n");
			break;
		}
		printf("接受服务器消息:%s\n",buff);
	}
	close(oldfd);
	return 0;
}
相关推荐
shimly1234569 分钟前
tcpdump 用法示例
网络·测试工具·tcpdump
sszdzq32 分钟前
Docker
运维·docker·容器
book012136 分钟前
MySql数据库运维学习笔记
运维·数据库·mysql
bugtraq20212 小时前
XiaoMi Mi5(gemini) 刷入Ubuntu Touch 16.04——安卓手机刷入Linux
linux·运维·ubuntu
xmweisi2 小时前
【华为】报文统计的技术NetStream
运维·服务器·网络·华为认证
VVVVWeiYee2 小时前
BGP配置华为——路径优选验证
运维·网络·华为·信息与通信
陆鳐LuLu2 小时前
日志管理利器:基于 ELK 的日志收集、存储与可视化实战
运维·elk·jenkins
DC_BLOG2 小时前
Linux-GlusterFS进阶分布式卷
linux·运维·服务器·分布式
yourkin6663 小时前
TCP...
服务器·网络·tcp/ip
cookies_s_s3 小时前
Linux--进程(进程虚拟地址空间、页表、进程控制、实现简易shell)
linux·运维·服务器·数据结构·c++·算法·哈希算法