poll函数 多路I/O转接服务器 linux网络编程

poll

程序思路同select函数用法
函数原型:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数1:传入传出参数,返回监听集响应状态
参数2:监听数量
参数3:超时判断,一般设为-1.

结构体定义
struct pollfd {
int fd; /* file descriptor /
short events; /
requested events /
short revents; /
returned events */
};

优化:
1.可以突破1024个文件描述符限制
2.监听、返回集合分离
3.poll自带监听描述符结构体数组,搜索范围可以缩小

修改文件描述符上限

cat /proc/sys/fs/file-max 查看文件描述符上限 (硬件层面)
sudo vi /etc/security/limits.conf文件描述符设置文件,打开,尾部加上下面语句
soft nofile(软限制)
hard nofile(硬限制)

服务器端

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<poll.h>
#include<errno.h>
#include<ctype.h>
#include<string.h>
#include<strings.h>

#define MAXLINE 80
#define SERV_PORT 6666
#define OPEN_MAX 1024

int main(int argc, char *argv[] )
{
    int i,j,maxi,listenfd,connfd,sockfd;
    int nready;   //接收poll返回值
    ssize_t n;

    char buf[MAXLINE],str[INET_ADDRSTRLEN];
    socklen_t clien_len;
    struct pollfd client[OPEN_MAX];  //保存监听文件描述符
    struct sockaddr_in clie_addr,serv_addr;

    listenfd=socket(AF_INET,SOCK_STREAM,0);

    int opt=1;
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//端口复用

    bzero(&serv_addr,sizeof(serv_addr));
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    serv_addr.sin_port=htons(SERV_PORT);

    bind(listenfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
    listen(listenfd,128);
    
    client[0].fd=listenfd;//要监听的第一个文件描述符存入,处理新客户端连接请求
    client[0].events=POLLIN;//监听读事件

    for(i=1;i<OPEN_MAX;i++)
        client[i].fd=-1;

    maxi=0;//数组中存入元素下标最大值,poll函数参数要求

    while(1)
    {
        nready=poll(client,maxi+1,-1);//阻塞监听客户端请求
        //client[i].revents会返回响应状态
        if(client[0].revents& POLLIN)//新客户端连接请求
        {
            clien_len=sizeof(clie_addr);
            connfd=accept(listenfd,(struct sockaddr *)&clie_addr,&clien_len);
            printf("*****************************************************\n");
            printf("new client connect: ip: %s ---port: %d\n",
                    inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr,str,sizeof(str)),
                    ntohs(clie_addr.sin_port));

            for(i=1;i<OPEN_MAX;i++)
            {
                if(client[i].fd<0)
                {
                    client[i].fd=connfd;//找到数组中空闲位置,放入新客户端
                    break;
                }
            }

            if(i==OPEN_MAX)
            {
                perror("too many clients");
                exit(1);
            }

            client[i].events=POLLIN;//设置刚刚返回的connfd,监听读事件
            if(i>maxi)
                maxi=i;//更新maxi,确保最大
            if(--nready<=0)//没有更多就绪事件,继续回到poll阻塞等待
                continue;
        }
        for(i=1;i<=maxi;i++)
        {
            if((sockfd=client[i].fd)<0)
                continue;
            if(client[i].revents & POLLIN)//寻找可读相应的客户端
            {
                if((n=read(sockfd,buf,sizeof(buf)))<0)
                {
                    if(errno==ECONNRESET)//收到RST标志位
                    {
                        printf("client[%d] aborted connection\n",i);
                        close(sockfd);
                        client[i].fd=-1;
                    }
                    else
                    {
                        perror("read error!");
                        exit(1);
                    }
                }
                else if(n==0)//客户端关闭连接
                {
                    printf("client[%d] closed \n",i);
                    close(sockfd);
                    client[i].fd=-1;
                }
                else
                {
                    for(j=0;j<n;j++)
                        buf[j]=toupper(buf[j]);
                    write(sockfd,buf,n);
                }
                if(--nready<=0)//没有多余就绪事件,返回poll阻塞等待
                    break;
            }
        }
    }
    return 0;
}

客户端

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<string.h>

#define SERV_IP "127.0.0.1"
#define SERV_PORT  6666
int main()
{
    int cfd,sfd;
    struct sockaddr_in serv_addr;
    socklen_t serv_addr_len;
    char buf[BUFSIZ],clien_ip[BUFSIZ];
    int n;
    char *find;

    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons(SERV_PORT);//转换为网络字节序
    //serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY可以自行寻找ip
    inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);

    cfd=socket(AF_INET,SOCK_STREAM,0);//创建本地套接字

    // bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//绑定,客户端隐式绑定

    connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr) );

    while(1)
    {
        memset(buf,0,sizeof(buf));
        fgets(buf,sizeof(buf),stdin);//从输入端读一行数据存入缓存区中
        find=strchr(buf,'\n');
        if(find)
            *find='\0';//去掉fgets中的换行符
        write(cfd,buf,strlen(buf));
        n=read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,n);
        printf("\n");
    }   
    close(cfd);
    return 0;
}

测试结果

客户端1:
在这里插入图片描述
客户端2:

在这里插入图片描述
服务端:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值