利用C语言基于poll实现TCP回声服务器的多路复用模型

利用C语言实现基于 poll的TCP回声服务器,可以高效地处理多个客户端连接,这种模型被称为多路复用。下面是一个精简而专业的指南,展示了如何通过 poll来实现这一目标。

关键概念

  • TCP服务器:一种在网络编程中常用的服务器模型,用于提供可靠的、面向连接的通信。
  • 回声服务器:这种服务器简单地将接收到的数据回发给发送者。
  • poll系统调用 :poll提供了一种方式,允许程序监视多个文件描述符集合中的事件,是多路复用编程的一种方式。

实现步骤

  1. 初始化服务器

    • 创建一个TCP套接字。
    • 将套接字绑定到服务器地址(IP地址和端口)。
    • 监听套接字,准备接受客户端连接。
  2. 设置 poll

    • 创建 pollfd结构体数组,以跟踪和管理多个套接字。
    • 将监听套接字加入到 pollfd数组中,设置相应的事件为 POLLIN,以表明我们对可读事件感兴趣。
  3. 事件循环

    • 使用 poll系统调用等待事件发生。poll调用将阻塞,直到一个或多个套接字准备好进行I/O操作。

    • 遍历 pollfd数组,检查哪些套接字有事件发生。

      • 如果监听套接字有事件发生,接受新的客户端连接,并将新的套接字添加到 pollfd数组中。
      • 如果是已连接的客户端套接字上有事件发生,读取数据并回发给客户端。如果读取到的数据长度为0(客户端关闭连接),则关闭套接字并从 pollfd数组中移除。
  4. 数据处理

    • 从活跃的客户端套接字读取数据。
    • 将接收到的数据原封不动地发送回客户端。
  5. 清理与资源管理

    • 一旦服务完成,关闭所有打开的套接字。
    • 确保在退出程序前释放所有分配的资源。

示例代码

下面是一个简化的示例代码,展示了如何使用 poll来实现多路复用的TCP回声服务器:

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <poll.h>

#define MAX_CLIENTS 10
#define BUFFER_SIZE 1024

int main() {
    int sockfd, newsockfd, portno = 12345;
    struct sockaddr_in serv_addr, cli_addr;
    socklen_t clilen;
    struct pollfd fds[MAX_CLIENTS];
    int nfds = 1, current_size = 0, i, ret;
    char buffer[BUFFER_SIZE];

    // 创建TCP套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("ERROR opening socket");
        exit(1);
    }

    // 绑定到本地地址
    memset((char *)&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("ERROR on binding");
        exit(1);
    }

    // 监听
    listen(sockfd, 5);

    // 初始化pollfd结构
    memset(fds, 0 , sizeof(fds));
    fds[0].fd = sockfd;
    fds[0].events = POLLIN;

    // 循环等待
    while (1) {
        ret = poll(fds, nfds, -1);
        if (ret < 0) {
            perror("ERROR on poll");
            exit(1);
        }

        // 检查是否是新连接
        if (fds[0].revents & POLLIN) {
            clilen = sizeof(cli_addr);
            newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
            if (newsockfd < 0) {
                perror("ERROR on accept");
                continue;
            }
            fds[nfds].fd = newsockfd;
            fds[nfds].events = POLLIN;
            nfds++;
        }

        // 检查数据接收
        for (i = 1; i < nfds; i++) {
            if (fds[i].revents & POLLIN) {
                memset(buffer, 0, BUFFER_SIZE);
                ret = read(fds[i].fd, buffer, BUFFER_SIZE);
                if (ret < 0) {
                    perror("ERROR reading from socket");
                    close(fds[i].fd);
                    continue;
                } else if (ret == 0) {
                    close(fds[i].fd);
                    fds[i].fd = -1; // 标记为不用
                } else {
                    write(fds[i].fd, buffer, ret);
                }
            }
        }
    }

    close(sockfd);
    return 0;
}

此代码仅为示例,展示了如何基于 poll实现多路复用的TCP回声服务器的基本框架。在实际应用中,你可能需要对其进行扩展或修改,以满足具体的需求。

相关推荐
浩浩测试一下2 小时前
Linux 底层知识点 1
linux·运维·服务器
Eloudy2 小时前
全文 - IMEX 第01节 -IMEX overview
运维·服务器·网络
Escalating_xu2 小时前
【Linux 网络编程】TCP 跨平台实战:用 Windows 客户端访问 Linux 服务器
linux·服务器·网络
发量惊人的中年网工2 小时前
分公司访问总部ERP慢怎么办?SD-WAN组网的排查与验收要点
服务器·开发语言·php
翼龙云_cloud3 小时前
亚马逊云服务器服务代理商:Bedrock 实践经验 Serverless 架构下的 AI 自动化落地
服务器·架构·serverless·云计算·aws
忆挽篱笙歌3 小时前
环境变量,本地变量
linux·运维·服务器
小天源6 小时前
让访问数据可解释:IP 地球大屏、地区库更新与运行维护设计
网络·网络协议·tcp/ip
张宇Joaquin6 小时前
AMD uProf 工具采集微架构特征使用介绍
服务器
老李IT笔记6 小时前
连不上不一定是网不好:新系统不认的服务端配置卡在哪一档
运维·服务器·网络
刚入门的大一新生7 小时前
Linux-进程池
linux·运维·服务器