Socket编程-poll函数流程

代码实例

#include  <unistd.h>
#include  <sys/types.h>       /* basic system data types */
#include  <sys/socket.h>      /* basic socket definitions */
#include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */
#include  <arpa/inet.h>       /* inet(3) functions */
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <poll.h> /* poll function */
#include <limits.h>
#define MAXLINE 10240
#ifndef OPEN_MAX
#define OPEN_MAX 40960
#endif
 
void handle(struct pollfd* clients, int maxClient, int readyClient);
 
int  main(int argc, char **argv)
{
    int servPort = 6888; // 端口信息
    int listenq = 1024; // listen等待的最大文件描述符
    int listenfd, connfd;
    struct pollfd clients[OPEN_MAX]; // poll打开的最大文件描述符
    int  maxi;
    socklen_t socklen = sizeof(struct sockaddr_in); // 地址长度
    struct sockaddr_in cliaddr, servaddr; // 服务器地址和客户端地址
    char buf[MAXLINE]; // bug长度
    int nready;
 
    // 初始化服务器地址
    bzero(&servaddr, socklen);
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(servPort);
 
    // 创建监听套接字
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0) {
        perror("socket error");
    }
 
    // 保证地址可以重复利用
    int opt = 1;
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        perror("setsockopt error");
    }
 
    // 绑定监听套接字和服务器地址
    if(bind(listenfd, (struct sockaddr *) &servaddr, socklen) == -1) {
        perror("bind error");
        exit(-1);
    }
    if (listen(listenfd, listenq) < 0) {
        perror("listen error");   
    }
 
    // clients中的第一个套接字是监听套接字
    clients[0].fd = listenfd;
    // clients中的第一个套接字,我们关心的事件是POLLIN事件
    clients[0].events = POLLIN;
    int i;
    // 其他套接字置为-1
    for (i = 1; i< OPEN_MAX; i++)
        clients[i].fd = -1;
    maxi = listenfd + 1;
 
    printf("pollechoserver startup, listen on port:%d\n", servPort);
    printf("max connection is %d\n", OPEN_MAX);
 
    for ( ; ; )  {
        printf("For\n");
        // poll 函数,clients集合,最大文件描述符,不超时
        nready = poll(clients, maxi + 1, -1);
        printf("Poll End\n");
        //printf("nready is %d\n", nready);
        if (nready == -1) {
            perror("poll error");
        }
        // 如果clients中的第一个文件描述符有POLLIN事件
        if (clients[0].revents & POLLIN) {
            // 建立连接,返回已连接套接字
            connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &socklen);
            sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
            printf(buf, "");
 
            // 将已连接套接字加入空闲位置,并对POLLIN事件感兴趣
            for (i = 0; i < OPEN_MAX; i++) { if (clients[i].fd == -1) { clients[i].fd = connfd; clients[i].events = POLLIN; break; } } // 如果没有空闲位置了,则表明clients集合已经满了,关闭套接字 if (i == OPEN_MAX) { fprintf(stderr, "too many connection, more than %d\n", OPEN_MAX); close(connfd); continue; } if (i > maxi)
                maxi = i;
 
            --nready;
        }
 
        handle(clients, maxi, nready);
    }
}
 
void handle(struct pollfd* clients, int maxClient, int nready) {
    int connfd;
    int i, nread;
    char buf[MAXLINE];
    printf("Print\n");
 
    if (nready == 0)
        return;
 
    for (i = 1; i< maxClient; i++) {
        connfd = clients[i].fd;
        if (connfd == -1)
            continue;
        if (clients[i].revents & (POLLIN | POLLERR)) {
            nread = read(connfd, buf, MAXLINE);//读取客户端socket流
            if (nread < 0) {
                perror("read error");
                close(connfd);
                clients[i].fd = -1;
                continue;
            }
            if (nread == 0) {
                printf("client close the connection");
                close(connfd);
                clients[i].fd = -1;
                continue;
            }
 
            write(connfd, buf, nread);//响应客户端 
            if (--nready <= 0)//没有连接需要处理,退出循环
                break;
        }
    }
}

poll流程图

poll函数和select函数类似,仍然不是异步的

poll函数流程图

 

 

一个回复在 “Socket编程-poll函数流程

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部