利用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回声服务器的基本框架。在实际应用中,你可能需要对其进行扩展或修改,以满足具体的需求。

相关推荐
小绫网络安全17 分钟前
Kali Linux渗透测试入门教程:从零搭建到实战攻防
linux·运维·服务器
西安景驰电子30 分钟前
《PTP精确时间协议系列》第一篇:从原理到应用,全面解读IEEE 1588
linux·运维·服务器·开发语言·网络·windows·php
Bruce_Liuxiaowei40 分钟前
基于微步在线威胁情报的公网 IP 攻击迹象监测:threatbook_query 脚本全解析与 BruceSec 平台整合实践
数据库·tcp/ip·安全·网络安全·智能体
luj_17681 小时前
塔防牌:策略与卡牌的智慧碰撞
服务器·c语言·开发语言·经验分享·算法
水无痕simon1 小时前
3 短信应用场景以及平台架构
java·服务器
wuyk5551 小时前
3.链表:用指针串联的动态数据结构
c语言·开发语言·数据结构·链表
80s7772 小时前
独享住宅IP、长效代理ip是什么?有哪些作用?
网络·网络协议·tcp/ip
IPdodo_2 小时前
静态 IP、住宅 IP 和固定出口有什么区别?开发场景选型指南
服务器·网络·网络协议·tcp/ip·代理ip
Lzh编程小栈2 小时前
【嵌入式底层】SPI超透彻详解:通信原理、四线结构、四种模式、寄存器底层 + 面试全集
c语言·stm32·单片机·面试·职场和发展
_ZHOURUI_H_2 小时前
Unity TCP底层极限拆解:粘包、半包、CRC、序列号、双缓冲到底怎么一起工作的?
网络·网络协议·tcp/ip·游戏·unity·游戏引擎·游戏开发