linux/unix网络编程之 poll

转自http://www.cnblogs.com/zhuwbox/p/4222382.html

poll 与 select 很类似,都是对描述符进行遍历,查看是否有描述符就绪。如果有就返回就绪文件描述符的个数将。poll 函数如下:

  #include <poll.h>

  int poll(struct pollfd *fdarray, unsigned long nfds, int timeout)

  第一个参数指向结构数组第一个元素的指针,每个数组都是一个 pollfd 结构,用于指定测试某个给定描述符 fd 的条件。

  struct pollfd

  {

    int fd;

    short events;//关心 fd 上发生的事件

    short revents;//fd 实际上上发生的事件

  }

  要测试的条件由 events 成员指定,函数在相应的 revents 成员中返回该描述符的状态(每个描述符都有两个变量,一个为调用值,另一个为返回结果,从而避免值-结果参数)这两个成员中的每一个都由指定某个特定条件的一位或多位组合而成。下标列出指定 events 标志以及测试 revents 标志的一些常值。

  ----------------------------+---------------------------------------+---------------------------------------+----------------------------------------+

     常量         |  能做为 events 的输入吗?    | 能作为revents 的结果吗? | 说明             |

  ----------------------------+---------------------------------------+---------------------------------------+----------------------------------------+

         POLLIN      |    能         |       能      |  普通或者优先级带数据可读    |

         POLLRDNORM    |    能         |       能      |  普通数据可读          |

     POLLRDBAND          |    能         |       能      |  优先级带数据可读        |

         POLLPRI      |    能         |       能      |  高优先级数据可读      |

  ----------------------------+---------------------------------------+---------------------------------------+----------------------------------------+

         POLLOUT       |    能         |       能      | 普通数据可写           |

         POLLWRNORM   |    能         |       能      | 普通数据可写        |

  POLLWRBAND    |    能         |       能      | 优先级带数据可写      |

  ----------------------------+---------------------------------------+--------------------------------------+-----------------------------------------+

         POLLERR       |              |       能      | 发生错误          |

         POLLHUP       |              |       能      | 发生挂起          |

  POLLNVAL                |              |         能      | 描述字不是一个打开的文件     |

  -----------------------------+--------------------------------------+---------------------------------------+----------------------------------------+

  第二个参数 nfds 制定数组中元素个数。第三个参数指定 poll 函数返回前等待多长时间。 INFTIM 表示永远等待, 0 代表立即返回, > 0 等待指定数目的秒数。

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <limits.h>
#include <poll.h>
#include <sys/stropts.h>
#include <signal.h>
#define MAXLINE 5
#define OPEN_MAX 1024
#define SA struct sockaddr

int main()
{
    int listenfd, connfd, sockfd, i, maxi;
    int nready;
    socklen_t clilen;
    ssize_t n;
    char buf[MAXLINE];
    struct pollfd client[OPEN_MAX];
    struct sockaddr_in servaddr, cliaddr;
    //创建监听套接字
    if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("socket() error!");
        exit(0);
    }
    //先要对协议地址进行清零
    bzero(&servaddr,sizeof(servaddr));
    //设置为 IPv4 or IPv6
    servaddr.sin_family = AF_INET;
    //绑定本地端口号
    servaddr.sin_port    = htons(9805);
    //任何一个 IP 地址,让内核自行选择
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    //绑定套接口到本地协议地址
    if(bind(listenfd, (SA *) &servaddr,sizeof(servaddr)) < 0)
    {
        printf("bind() error!");
        exit(0);
    }
    //服务器开始监听
    if(listen(listenfd,5) < 0)
    {
        printf("listen() error!");
        exit(0);
    }
    client[0].fd = listenfd;
    client[0].events = POLLRDNORM;//关心监听套机字的读事件
    for(i = 1; i < OPEN_MAX; ++i)
    {
        client[i].fd = -1;
    }
    maxi = 0;
    for(;;)
    {
        nready = poll(client, maxi + 1, -1);
        if(client[0].revents & POLLRDNORM)
        {
            clilen = sizeof(cliaddr);
            //accept 的后面两个参数都是值-结果参数,他们的保留的远程连接电脑的信息,如果不管新远程连接电脑的信息,可以将这两个参数设置为 NULL
            connfd = accept(listenfd, (SA *) &cliaddr, &clilen);
            if(connfd < 0)
            {
                continue;
            }
            for(i = 1; i < OPEN_MAX; ++i)
            {
                if(client[i].fd < 0)
                    client[i].fd = connfd;
                break;
            }
            if(i == OPEN_MAX)
            {
                printf("too many clients");
                exit(0);
            }
            client[i].events = POLLRDNORM;
            if(i > maxi)
            {
                maxi = i;
            }
            if(--nready <=0 )
                continue;
        }
        for(i = 1; i < OPEN_MAX; ++i)
        {
            if((sockfd = client[i].fd) < 0)
            {
                continue;
            }
            if(client[i].revents & POLLRDNORM | POLLERR)
            {
                if((n = read(sockfd, buf, MAXLINE)) < 0)
                {
                    if(errno == ECONNRESET)
                    {
                        close(sockfd);
                        client[i].fd = -1;
                    }
                    else
                    {
                        printf("read error!\n");
                    }
                }
                else if(n == 0)
                {
                    close(sockfd);
                    client[i].fd = -1;
                }
                else
                {
                    write(sockfd, buf,  n);
                }
                if(--nready <= 0)
                    break;
            }
        }
    }
}
时间: 2024-10-13 19:52:27

linux/unix网络编程之 poll的相关文章

linux/unix网络编程之 select

转自http://www.cnblogs.com/zhuwbox/p/4221934.html linux 下的 select 知识点 unp 的第六章已经描述的很清楚,我们这里简单的说下 select 的作用,并给出 select 的客户端实例.我们知道 select 是IO 多路复用的一个最简单支持,poll 和 epoll 是 select 的升级版.在 UNIX 网络编程第五章读书笔记 我们遇到这样一个问题:当客户端阻塞在 fgets() 等待客户输入的时候,服务器端断开连接.而客户端却

linux/unix网络编程之epoll

转载自 Linux epoll模型 ,这篇文章讲的非常详细! 定义: epoll是Linux内核为处理大批句柄而作改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著的减少程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率.因为它会复用文件描述符集合来传递结果而不是迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一个原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符

Unix网络编程之IO复用

上篇存在的问题 在上一篇TCP套接字中,还存在着一些问题. 当客户端连接上服务器后,阻塞于从标准输入读入信息的状态,若此时服务器进程被杀死,即使给客户TCP发来一个 FIN结束分节,但是由于客户处于阻塞状态,它将看不到这个EOF,直到读取之后,此时可能已经过去了很长时间. 因此进程需要一种能力,让内核同时检测多个IO口是否就绪,这个能力就称为IO复用.这是由select和poll两个函数 支持的. select函数 作用 允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或

Linux/Unix C编程之的perror函数,strerror函数,errno

#include <stdio.h> // void perror(const char *msg); #include <string.h> // char *strerror(int errnum); #include <errno.h> //errno ? errno 是错误代码,在 errno.h头文件中: perror是错误输出函数,输出格式为:msg:errno对应的错误信息(加上一个换行符): strerror?是通过参数 errnum (就是errno)

linux高性能服务器编程之poll

一.概述: 和select不同的是,poll使用一个pollfd来指向所要监听的fd,事件,返回事件.(pollfd下面详细讲.) 并且poll没有最大的文件描述符数量的限制,是自己定义一个pollfd数组来实现的. 它的缺点和select差不多,即 (1)每次调用poll,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大(2)当要确定一个文件描述符的状态时,都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 二.poll介绍篇:  int poll(struct p

UNIX网络编程之epoll的 accept , read , write

本文转载自:http://www.it165.net/os/html/201308/5868.html 非阻塞模式下的网络编程,非阻塞模式常常需要不停地进行轮询,大量耗费CPU资源,这种方式并不可取. 在一个非阻塞的socket上调用read/write函数,返回EAGAIN或者EWOULDBLOCK(注:EAGAIN就是EWOULDBLOCK). 从字面上看,意思是: EAGAIN: 再试一次 EWOULDBLOCK:如果这是一个阻塞socket, 操作将被block perror输出:Res

unix网络编程之listen()详解

Unix网络编程描述如下: #include <sys/socket.h> int listen(int sockfd,  int backlog); 返回:若成功则为0,  若出错则为-1: 本函数通常应该在调用socket和bind这两个函数之后,并在调用accept函数之前调用: 为了理解其中的backlog参数,我们必须认识到内核为任何一个给定的监听套接字维护两个队列: (1)未完成连接队列(incomplete connection queue),

Unix网络编程之UDP常见缺陷与实例

UDP与TCP相比,各有优缺点,下来来列举一下UDP的缺点: 1.UDP是一种不可靠的协议(缺乏流量控制) 实例代码: //server.c #include <stdlib.h> #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> int main() { int sockfd; struct sockaddr_in ser

Unix网络编程之UDP实例

首先先看一下UDP客户/服务器交互的典型情形,如下图: 由上图可知,客户端程序不需要与服务器端建立连接,只需要调用sendto函数向服务器发送数据,或者调用recvfrom函数从服务器接收数据即可.最明显地特点就是服务器端只是比客户端多调用了一个bind函数来显式绑定一个端口.事实上客户端也可以通过bind来绑定端口,只不过没有那个必要. 实例代码: //server.c #include <stdlib.h> #include <stdio.h> #include <sys