多路IO复用--poll实现

函数参数说明

 int poll(struct pollfd *fds, nfds_t nfds, int timeout);
 struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
           };
           
Instructions on Linux: poll() performs a similar task to select(2): it waits for one of a set of file descriptors to become ready to perform I/O.
	POLLIN			普通或带外优先数据可读,即POLLRDNORM | POLLRDBAND
	POLLRDNORM		数据可读
	POLLRDBAND		优先级带数据可读
	POLLPRI 		高优先级可读数据
	POLLOUT			普通或带外数据可写
	POLLWRNORM		数据可写
	POLLWRBAND		优先级带数据可写
	POLLERR 		发生错误
	POLLHUP 		发生挂起
	POLLNVAL 		描述字不是一个打开的文件

	nfds 			监控数组中有多少文件描述符需要被监控
timeout 		毫秒级等待
		-1:阻塞等,#define INFTIM -1 				Linux中没有定义此宏
		=0:立即返回,不阻塞进程
		>0:等待指定毫秒数,如当前系统时间精度不够毫秒,向上取值
		
如果不再监控某个文件描述符时,可以把pollfd中,fd设置为-1,poll不再监控此pollfd,下次返回时,把revents设置为0

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>
#define MAXLINE     80
#define SERV_PORT   6666
#define OPEN_MAX    1024

int main(int argc, char *argv[])
{
    int listenfd = 0;
    int connfd = 0;
    int sockfd = 0;
    int nready;
    char buf[MAXLINE],str[INET_ADDRSTRLEN];
    struct pollfd client[OPEN_MAX];

    listenfd = Socket(AF_INET,SOCK_STREAM,0);
    int opt = 1;
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    struct sockaddr_in servaddr;
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    Bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    Listen(listenfd,128);

    memset(&client,-1,OPEN_MAX);//用-1初始化client[].fd里剩下元素

    client[0].fd = listenfd;
    client[0].events = POLLRDNORM;//listenfd 监听普通读事件
    int i = 0;
    nfds_t maxi = 0;   //client[]数组有效元素中最大元素下标
    for(;;)
    {
        nready = poll(client, maxi + 1, -1); //阻塞
        if(client[0].revents & POLLRDNORM)      //有客户端链接请求
        {
            struct sockaddr_in clienaddr;
            ssize_t cliensize = sizeof(clienaddr);
            bzero(&clienaddr,sizeof(clienaddr));
            connfd = Accept(listenfd,(struct sockaddr *)&clienaddr,&cliensize);
            strcpy(str,inet_ntop(AF_INET,&clienaddr.sin_addr,str,sizeof(str)));
            printf("received from %s at port %d\n",str,ntohs(clienaddr.sin_port));
            for(i = 1;i<OPEN_MAX;i++)
            {
                if(client[i].fd < 0)
                {
                    client[i].fd = connfd;//找到client[]中空闲的位置,存放accept返回的connfd
                    break;
                }
            }

            if(i == OPEN_MAX)
            {
                perr_exit("too many clients");
            }
            client[i].events = POLLRDNORM;      //设置刚刚返回的connfd,监控读事件
            if(i > maxi)
            {
                maxi = i;
            }
            if(--nready <= 0)
            {
                continue;
            }
        }
        for(i = 1; i <= maxi; i++)
        {
            sockfd = client[i].fd;
            if(sockfd < 0)
            {
                continue;
            }
            short int flag = POLLRDNORM | POLLERR;
            printf("client[%d].revents = 0x%x,flag = 0x%x,revents&flag = 0x%x\n",i,
                   client[i].revents,flag,(client[i].revents)&flag);
            if(client[i].revents & (POLLRDNORM | POLLERR))
            {
                printf("--------------------\n");
                memset(buf,0,sizeof(buf));
                ssize_t n = Read(sockfd,buf,MAXLINE);
                if(n < 0)
                {
                    if(errno == ECONNRESET) //当收到 RST标志时
                    {
                        printf("client[%d] aborted connection\n",i);
                        Close(sockfd);
                        client[i].fd = -1;
                    }
                    else
                    {
                        perr_exit("read error");
                    }
                }
                else if(n == 0)
                {
                    printf("client[%d] closed connection\n",i);
                    Close(sockfd);
                    client[i].fd = -1;
                }
                else
                {
                    struct sockaddr_in sa;
                    int len = sizeof(sa);
                    if(!getpeername(sockfd, (struct sockaddr *)&sa, &len))
                    {
                        printf( "%s :%d-->%s\n", inet_ntoa(sa.sin_addr),ntohs(sa.sin_port),buf);
                    }
                    Write(sockfd,buf,n);//回射客户端
                }
                if(--nready <= 0)
                {
                    break;
                }
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值