Linux网络编程-7、poll实现多路IO转接服务器, TCP下的C/S模型优化, 两个阻塞 1新客户端connect建立连接 服务器accept阻塞 2旧客户端想发数据 服务器read阻塞

1、lfd = socket()建立监听套接字

2、setsockopt() 允许端口复用

3、bind() 给监听套接字绑定sockaddr地址结构

4、listen() 设置监听上限

5、ret = poll( &pfds) 小秘书只负责监听

6、对ret分类判断 解析读事件(都由谁产生) 就这2种:(新客户端想建立连接 + 旧客户端想发数据给服务器)

7、poll比select优化 遍历:哪个文件描述符产生读事件更高效 if (pfds[i].revents & POLLIN)

8、先分析pfds[0].revents 有无新客户端建立连接

9、新的客户端对应文件描述符加入监听数组中

10、更新监听文件描述符数组的有效个数

8、再分析其他的pfds[i].revents有无数据到达

9、旧客户端(已经建立连接的)要发数据给服务器

10、读数据

11、模拟数据处理

12、处理后的数据发给客户端

#include "wrap.h"
#include <arpa/inet.h>
#include <sys/time.h>
#include <ctype.h>
#include <poll.h>
#define PORT 9527
#define MAXLISTEN 128

int main(void)
{
    int lfd, cfd; // 监听 + 通信 套接字描述符
    int ret;
    int n; //读到的字节数
    char buf[BUFSIZ]; // 接收读到的数据
    struct sockaddr_in clientaddr;
    socklen_t clientaddrlen = sizeof(clientaddr); // 用于记录连接到服务器的客户端的ip + 端口号
    // 1、创建监听套接字
    lfd = Socket(AF_INET, SOCK_STREAM, 0);
    // 2、设置端口复用
    int opt = 1;
    ret = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
    if (ret == -1)
        sys_error("setsockopt error");
    // 3、绑定地址结构
    struct sockaddr_in saddr;
    socklen_t saddrlen = sizeof(saddr);
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(PORT); // 端口号转成网络字节序
    saddr.sin_addr.s_addr = htonl(INADDR_ANY); // ip地址转成网络字节序   
    Bind(lfd, (struct sockaddr *)&saddr, saddrlen);
    // 4、设置监听上限
    Listen(lfd, MAXLISTEN);
    // 5、poll小秘书只负责监听(1次调用, 监听1次)
    // 定义1个监听的文件描述符数组====代替select的监听读集合
    struct pollfd pfds[1024];
    pfds[0].fd = lfd; 
    pfds[0].events = POLLIN; 
    pfds[0].revents = 0; // 只监听lfd的读事件(有无新客户端建立连接)
    int nfds = 1; // 监听描述符数组中实际有效的文件描述符个数
    while (1)
    {
        ret = poll(pfds, nfds, 0); // 非阻塞轮询式监听 
        if (ret > 0) // 6、分析监听数组中哪几个文件描述符发生了读事件
        {
            // 7、先分析pfds[0].revents 有无新客户端建立连接
            if (pfds[0].revents & POLLIN)
            {
                cfd = Accept(lfd, (struct sockaddr *)&clientaddr, &clientaddrlen);
                // 打印客户端信息
                char cip[256];
                inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, cip, sizeof(cip));
                printf("新连接的客户端: ip %s port %d\n", cip, ntohs(clientaddr.sin_port));
                // 8、新的客户端对应文件描述符加入监听数组中
                pfds[nfds].fd = cfd;
                pfds[nfds].events = POLLIN;
                pfds[nfds].revents = 0;
                // 9、更新监听文件描述符数组的有效个数
                ++nfds;
            }
            // 7、再分析其他的pfds[i].revents有无数据到达
            for (int i = 1; i < nfds; ++i)
            {
                if (pfds[i].revents & POLLIN)
                {
                    // 8、旧客户端(已经建立连接的)要发数据给服务器
                    // 9、读数据
                    if ((n = read(pfds[i].fd, buf, BUFSIZ)) > 0) // 真有数据到达
                    {
                        // 10、模拟数据处理
                        for (int j = 0; j < n; ++j)
                            buf[i] = toupper(buf[i]);
                        // 11 、处理后的数据发给客户端
                        write(pfds[i].fd, buf, n);
                    }
                    else if (n == 0) // 旧客户端关闭连接
                    {
                        // 10、服务器也关闭连接
                        Close(pfds[i].fd);
                        // 11、该文件描述符剔除出去(从监听数组中)
                        // 数组整体前移
                        // --nfds; // 更新监听数组的有效文件描述符个数
                    }       
                }
            }
        }
        else if (ret == -1)
            sys_error("poll error");
    } 

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪呈祥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值