Linux网络编程之IO复用——Poll

Poll系统调用

poll系统调用和select类似,也是在指定时间内轮询一定数量的文件描述符,以 测试其是否有就绪者。

#include <poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);

struct pollfd
{
   
	int fd;				//文件描述符
	short events;		//注册的事件
	short revents;		//实际发生的事件,由内核填充
};
  • fds参数是一个pollfd类型的数组,它指定所有我们感兴趣的文件描述符上发生的可读、可写和异常等事件。
    其中fd成员指定文件描述符;events成员告诉poll监听fd上的哪些事件,它是一系列事件的按位或;revents成员则由内核修改,以通知应用程序fd上实际发生了哪些事件。
  • poll事件类型
  • nfds参数指定了被监听事件集合fds的大小。
   typedef unsigned long int nfds_t;
  • timeout则指定poll的超时值

poll编程实例

poll编程流程

/* * 1.创建socket-->bind-->listen * 2.创建一个数组存储socketfd和事件 并初始化数组 * 3.先将servicefd放入数组 * 4.循环:① 创建poll,然后处理连接 * ② 如果是新连接,放入数组并注册事件 * ③ 如果断开就从中删除 * ④ 都不是就收发数据 */

头文件tcp_socket.h


#include<iostream>
#include<assert.h>
#include<string.h>

#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>

#include<unistd.h>

#define BUFF_SIZE 128

using namespace std;
class Socket
{
   
public:
	Socket()
	{
   
		sockfd_ = socket(PF_INET, SOCK_STREAM, 0);
		assert(sockfd_ >= 0);
	}

	int Get_socket()
	{
   
		return sockfd_;
	}

	~Socket()
	{
   
		close(sockfd_);
	}
protected:
	int sockfd_;
};

class Socket_Ser :public Socket
{
   
public:
	Socket_Ser(const char* ip, int port = 6000, int backlog = 5)
	{
   
		struct sockaddr_in address;
		memset(&address, 0, sizeof(address));

		address.sin_family = AF_INET;
		address.sin_port = htons(port);
		address.sin_addr.s_addr = inet_addr(ip);

		int ret = bind(sockfd_, (struct sockaddr*)&address, sizeof(address));
		assert(ret != -1);

		ret = listen(sockfd_, backlog);
		assert(ret != -1);
	}

	int Accept()
	{
   
		struct sockaddr_in client;
		socklen_t len = sizeof(client);
		int connfd = accept(sockfd_, (struct sockaddr*)&client, &len);
		return connfd;
	}

	int Recv(int fd, char* buffer, int size)
	{
   
		int ret = recv(fd, buffer, size - 1, 0);
		if (ret == -1 || (strncmp(buffer, "end", 3) == 0))
		{
   
			return -1;
		}
	}

	void Send(int fd, const char* buffer, int size)
	{
   
		send(fd, buffer, size, 0);
	}

	void Close_client(int fd)
	{
   
		close(fd);
	}
};

class Socket_Cli :public Socket
{
   
public:
	Socket_Cli(const char* ip, int port = 6000)
	{
   
		struct sockaddr_in address;
		memset(&address, 0, sizeof(address));

		address.sin_family = AF_INET;
		address.sin_port = htons(port);
		address.sin_addr.s_addr = inet_addr(ip);

		int ret = connect(sockfd_, (struct sockaddr*)&address, sizeof(address));
		assert(ret != -1);
	}

	int Send(char* buffer, int size)
	{
   
		send(sockfd_, buffer, size, 0);
	}
};

头文件tcp_poll.h

#include"tcp_socket.h"
#include <poll.h>
#include <list>

#define PollSize 100
class Poll
{
   
public:
	Poll(const char* ip, int port = 6000, int backlog = 5) :ser(ip, port, backlog)
	{
   	
		for (int i = 0; i < PollSize; i++)		//数组初始化
		{
   
			cli_arr[i].fd = -1;
			cli_arr[i].events = 0;
		}
		Insert(ser.Get_socket(), POLLIN);
	}

public:
	void Deal()
	{
   
		UsingPoll();
		Deal_connect();
	}
private:
	void Insert(int fd, short events)
	{
   
		int i = 0;
		for (; i < PollSize; i++)
		{
   
			if (cli_arr[i].fd == -1)	//找到一个未用过的数组
			{
   
				cli_arr[i].fd = fd;
				cli_arr[i].events = events;
				break;
			}
		}
		if (i == PollSize) cout << "client array is full!" << endl;
	}

	void Delete(struct pollfd& PollFd)
	{
   
		ser.Close_client(PollFd.fd);
		PollFd.fd = -1;
		PollFd.events = 0;
	}

	void Deal_connect()
	{
   
		for (int i = 0; i < PollSize; i++)
		{
   
			if (cli_arr[i].fd == ser.Get_socket())		//服务器端
			{
   
				if (cli_arr[i].revents & POLLIN)	//新的连接请求
				{
   
					int connfd = ser.Accept();
					cout << "client " << connfd << "link" << endl;

					Insert(connfd, POLLIN | POLLRDHUP);		//注册
				}
			}
			else					//客户端发送数据
			{
   
				if (cli_arr[i].revents & POLLRDHUP)		//客户端断开
				{
   
					cout << "client " << cli_arr[i].fd << "unlink" << endl;
					Delete(cli_arr[i]);
				}
				else if (cli_arr[i].revents & POLLIN)	//客户端发送数据
				{
   
					char buffer[128] = {
    0 };
					ser.Recv(cli_arr[i].fd, buffer, 128);
					cout << "recv form " << cli_arr[i].fd << ":" << buffer << endl;
				}
			}
		}
	}

	int UsingPoll()
	{
   
		int n = poll(cli_arr, PollSize, -1);
		if (n <= 0)
		{
   
			cout << "poll error" << endl;
			return -1;
		}
	}
private:
	Socket_Ser ser;

	struct pollfd cli_arr[PollSize];
};

主文件tcp_poll.cpp

#include "tcp_poll.h"

int main(int argc, char* argv[])
{
   
	if (argc <= 1)
	{
   
		cout << "errno! please input again" << endl;
	}
	Poll mypoll(argv[1]);

	while (1)
	{
   
		mypoll.Deal();
	}
}

参考文献

[1]游双.Linux高性能服务器编程.机械工业出版社,2043.5.
全部评论

相关推荐

沉淀一会:1.同学你面试评价不错,概率很大,请耐心等待; 2.你的排名比较靠前,不要担心,耐心等待; 3.问题不大,正在审批,不要着急签其他公司,等等我们! 4.预计9月中下旬,安心过节; 5.下周会有结果,请耐心等待下; 6.可能国庆节前后,一有结果我马上通知你; 7.预计10月中旬,再坚持一下; 8.正在走流程,就这两天了; 9.同学,结果我也不知道,你如果查到了也告诉我一声; 10.同学你出线不明朗,建议签其他公司保底! 11.同学你找了哪些公司,我也在找工作。
点赞 评论 收藏
分享
Java抽象带篮子:难蚌,点进图片上面就是我的大头😆
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务