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

    科技2022-07-10  108

    目录

    Poll系统调用poll编程实例poll编程流程头文件tcp_socket.h头文件tcp_poll.h主文件tcp_poll.cpp 参考文献

    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.
    Processed: 0.013, SQL: 8