【Linux学习笔记56】TCP服务器IO模型之多路复用(一)POLL函数

引言

上一篇笔记介绍了多种TCP服务器处理多套接字的方法,本篇笔记主要内容是记录实现TCP服务器多路复用的POLL函数的使用方法。

实现思想

poll函数的原理
在这里插入图片描述

  • 假设服务器中有三个不同的套接字负责不同的任务
  • 为每个套接字建立独有的pollfd结构体
  • 并且在结构体中拥有events存放结构体负责的事件:读事件,写事件,报错事件等
  • 将以上的所有结构体组成一个结构体数组作为poll函数的参数以供使用

有数据来临的操作原理:

在这里插入图片描述

  • 当有连接请求,数据同时到达,会分配到相对应的Pollfd结构体中
  • socketfd收到连接请求后,系统会在revents自动生成连接就绪
  • connfd2收到数据后,系统会在revents自动生成读就绪
  • 此时,Poll函数会自动返回2

代码实现

server.c:

#include "head4sock.h"

int main(int argc, char **argv)
{
	int sockfd = Socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in srvaddr;
	socklen_t len =sizeof(srvaddr);
	bzero(&srvaddr,len);

	srvaddr.sin_family = PF_INET;
	srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	srvaddr.sin_port = htons(atoi(argv[1]));

	Bind(sockfd,(struct sockaddr *)&srvaddr,len);
	Listen(sockfd,3);
	int connfd = Accept(sockfd,NULL,NULL);

	//struct pollfd *fds = calloc(n,sizeof(struct pollfd));
  //当不知道需要监听多少个描述符的时候,定义为指针
	struct pollfd fds[2]; //监听两个描述符
	fds[0].fd = STDIN_FILENO;
	fds[0].events =POLLRDNORM | POLLERR; //只关心fd套接字上的读操作 和错误操作

	fds[1].fd = connfd;
	fds[1].events =POLLRDNORM | POLLERR;

	char buf[SIZE];
	while (1)
	{
		poll(fds,2,0);
		bzero(buf,SIZE);
		if (fds[0].revents & POLLRDNORM)  //如果条件成立,则有数据输入
		{
			fgets(buf,SIZE,stdin);
			write(connfd,buf,strlen(buf));
		}
		if (fds[0].revents & POLLERR) //如果条件成立,则发生错误
		{
			perror("stdin error");
			break;
		}
		if (fds[1].revents & POLLRDNORM)  //如果条件成立,则有数据输入
		{
			if(Read(connfd,buf,SIZE) ==0)
			break;
			printf("form peer:%s\n", buf);
		}
		if (fds[1].revents & POLLERR) //如果条件成立,则发生错误
		{
			perror("read() failed");
			break;
		}
	}
}

client.c:

#include "head4sock.h"

int main(int argc, char **argv)
{
	int sockfd = Socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in srvaddr;
	socklen_t len =sizeof(srvaddr);
	bzero(&srvaddr,len);

	srvaddr.sin_family = PF_INET;
	inet_pton(AF_INET,argv[1],&srvaddr.sin_addr);
	srvaddr.sin_port = htons(atoi(argv[2]));

	Connect(sockfd,(struct sockaddr *)&srvaddr,len);

	//struct pollfd *fds = calloc(n,sizeof(struct pollfd));
  //当不知道需要监听多少个描述符的时候,定义为指针
	struct pollfd fds[2]; //监听两个描述符
	fds[0].fd = STDIN_FILENO;
	fds[0].events =POLLRDNORM | POLLERR; //只关心fd套接字上的读操作 和错误操作

	fds[1].fd = sockfd;
	fds[1].events =POLLRDNORM | POLLERR;

	char buf[SIZE];
	while (1)
	{
		poll(fds,2,0);
		bzero(buf,SIZE);
		if (fds[0].revents & POLLRDNORM)  //如果条件成立,则有数据输入
		{
			fgets(buf,SIZE,stdin);
			write(sockfd,buf,strlen(buf));
		}
		if (fds[0].revents & POLLERR) //如果条件成立,则发生错误
		{
			perror("stdin error");
			break;
		}
		if (fds[1].revents & POLLRDNORM)  //如果条件成立,则有数据输入
		{
			if(Read(sockfd,buf,SIZE) ==0)
			break;
			printf("form peer:%s\n", buf);
		}
		if (fds[1].revents & POLLERR) //如果条件成立,则发生错误
		{
			perror("read() failed");
			break;
		}
	}

	return 0;
}

代码运行结果:

在这里插入图片描述

发布了91 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/RayCongLiang/article/details/101029816