C 实现TCP服务端(select、poll、epoll)

2023-05-16

       使用C简单的实现一个tcp server,包括常规server、多线程实现server、select实现server、poll实现server、epoll实现server。

        IO模型原理可以看上一篇文章

常规模式

#define MAXLEN 4096

int main(int argc, char **argv) {
  int listenfd, connfd, n;
  struct sockaddr_in servaddr;
  char buff[MAXLEN];

  if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }

  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(9999);

  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
    printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }

  if (listen(listenfd, 10) != 0) {
    printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }

  struct sockaddr_in client;
  socklen_t len = sizeof(client);
  if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1) {
    printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  printf("========waiting for client's request========\n");
  while (1) {
    n = recv(connfd, buff, MAXLEN, 0);
    if (n > 0) {
      buff[n] = '\0';
      printf("recv msg from client: %s\n", buff);

      send(connfd, buff, n, 0);
    } else if (n == 0) {
      close(connfd);
    }

  close(listenfd);
  return 0;
}

 多线程模式

        支持多个客户端并发连接。

#define MAXLEN 4096

void *client_routine(void *arg) {
  int connfd = *(int *)arg;
  char buff[MAXLEN];
  while (1) {
    int n = recv(connfd, buff, MAXLEN, 0);
    if (n > 0) {
      buff[n] = '\0';
      printf("recv msg from client: %s\n", buff);
      send(connfd, buff, n, 0);
    } else if (n == 0) {
      close(connfd);
      break;
    }
  }
  return NULL;
}

int main(int argc, char **argv) {
  int listenfd, connfd, n;
  struct sockaddr_in servaddr;
  char buff[MAXLEN];

  if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(9999);

  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
    printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  if (listen(listenfd, 10) != 0) {
    printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  while (1) {
    struct sockaddr_in client;
    socklen_t len = sizeof(client);
    if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1) {
      printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
      return 0;
    }
    pthread_t threadid;
    pthread_create(&threadid, NULL, client_routine, (void *)&connfd);
  }
  close(listenfd);
  return 0;
}

select模式

        单线程支持多个客户端连接。

#define MAXLEN 4096

void *client_routine(void *arg) {
  int connfd = *(int *)arg;
  char buff[MAXLEN];
  while (1) {
    int n = recv(connfd, buff, MAXLEN, 0);
    if (n > 0) {
      buff[n] = '\0';
      printf("recv msg from client: %s\n", buff);
      send(connfd, buff, n, 0);
    } else if (n == 0) {
      close(connfd);
      break;
    }
  }
  return NULL;
}

int main(int argc, char **argv) {
  int listenfd, connfd, n;
  struct sockaddr_in servaddr;
  char buff[MAXLEN];

  if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(9999);

  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
    printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  if (listen(listenfd, 10) != 0) {
    printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
fd_set rfds, rset, wfds, wset;
  FD_ZERO(&rfds);          /*将rfds清零使集合中不含任何fd*/
  FD_SET(listenfd, &rfds); /*将fd加入rfds集合*/

  FD_ZERO(&wfds);

  int max_fd = listenfd;

  while (1) {
    rset = rfds;
    wset = wfds;

    int nready = select(max_fd + 1, &rset, &wset, NULL, NULL);

    /*在调用select()函数后,用FD_ISSET来检测fd是否在set集合中,当检测到fd在set中则返回真,否则,返回假(0)*/
    if (FD_ISSET(listenfd, &rset)) {
      struct sockaddr_in client;
      socklen_t len = sizeof(client);
      if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == 1) {
        printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
      }

      FD_SET(connfd, &rfds);

      if (connfd > max_fd) max_fd = connfd;

      if (--nready == 0) continue;
    }

    int i = 0;
    for (i = listenfd + 1; i <= max_fd; i++) {
      if (FD_ISSET(i, &rset)) {
        n = recv(i, buff, MAXLEN, 0);
        if (n > 0) {
          buff[n] = '\0';
          printf("recv msg from client: %s\n", buff);

          FD_SET(i, &wfds);
        } else if (n == 0) {
          FD_CLR(i, &rfds); /*将fd从set集合中清除*/
          close(i);
        }
        if (--nready == 0) break;
      } else if (FD_ISSET(i, &wset)) {
        send(i, buff, n, 0);
        FD_SET(i, &rfds);
        FD_CLR(i, &wfds); /*将fd从wfds集合中清除*/
      }
    }
  }
  close(listenfd);
  return 0;
}

 

poll 模式

#define MAXLEN 4096

void *client_routine(void *arg) {
  int connfd = *(int *)arg;
  char buff[MAXLEN];
  while (1) {
    int n = recv(connfd, buff, MAXLEN, 0);
    if (n > 0) {
      buff[n] = '\0';
      printf("recv msg from client: %s\n", buff);
      send(connfd, buff, n, 0);
    } else if (n == 0) {
      close(connfd);
      break;
    }
  }
  return NULL;
}

int main(int argc, char **argv) {
  int listenfd, connfd, n;
  struct sockaddr_in servaddr;
  char buff[MAXLEN];

  if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(9999);

  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
    printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  if (listen(listenfd, 10) != 0) {
    printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
struct pollfd fds[POLL_SIZE] = {0};
  fds[0].fd = listenfd;
  fds[0].events = POLLIN;

  int max_fd = listenfd;
  int i = 0;
  for (i = 1; i < POLL_SIZE; i++) {
    fds[i].fd = -1;
  }

  while (1) {
    int nready = poll(fds, max_fd + 1, -1);
    printf("nready: %d \n", nready);
    if (fds[0].revents & POLLIN) {
      struct sockaddr_in client;
      socklen_t len = sizeof(client);
      if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1) {
        printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
      }

      printf("accept \n");
      fds[connfd].fd = connfd;
      fds[connfd].events = POLLIN;

      if (connfd > max_fd) max_fd = connfd;

      if (--nready == 0) continue;
    }

    for (i = listenfd + 1; i <= max_fd; i++) {
      if (fds[i].revents & POLLIN) {
        n = recv(i, buff, MAXLEN, 0);
        if (n > 0) {
          buff[n] = '\0';
          printf("recv msg from client: %s\n", buff);
          fds[i].events = POLLOUT;
          // send(i, buff, n, 0);
        } else if (n == 0) {
          fds[i].fd = -1;
          close(i);
        }
        if (--nready == 0) break;
      } else if (fds[i].revents & POLLOUT) {
        send(i, buff, n, 0);
        fds[i].events = POLLIN;
      }
    }
  }
  close(listenfd);
  return 0;
}

epoll模式

#define MAXLEN 4096

void *client_routine(void *arg) {
  int connfd = *(int *)arg;
  char buff[MAXLEN];
  while (1) {
    int n = recv(connfd, buff, MAXLEN, 0);
    if (n > 0) {
      buff[n] = '\0';
      printf("recv msg from client: %s\n", buff);
      send(connfd, buff, n, 0);
    } else if (n == 0) {
      close(connfd);
      break;
    }
  }
  return NULL;
}

int main(int argc, char **argv) {
  int listenfd, connfd, n;
  struct sockaddr_in servaddr;
  char buff[MAXLEN];

  if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(9999);

  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
    printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  if (listen(listenfd, 10) != 0) {
    printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
    return 0;
  }
  int epfd = epoll_create(1);  // init size

  struct epoll_event events[POLL_SIZE] = {0};
  struct epoll_event ev;

  ev.events = EPOLLIN;
  ev.data.fd = listenfd;

  epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);

  while (1) {
    int nready = epoll_wait(epfd, events, POLL_SIZE, 5);
    if (nready == -1) {
      continue;
    }

    int i = 0;
    for (i = 0; i < nready; i++) {
      int clientfd = events[i].data.fd;
      if (clientfd == listenfd) {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) ==
            -1) {
          printf("accept socket error: %s(errno: %d)\n", strerror(errno),
                 errno);
          return 0;
        }
        printf("accept\n");
        ev.events = EPOLLIN;
        ev.data.fd = connfd;
        epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
      } else if (events[i].events & EPOLLIN) {
        n = recv(clientfd, buff, MAXLEN, 0);
        if (n > 0) {
          buff[n] = '\0';
          printf("recv msg from client: %s\n", buff);

          send(clientfd, buff, n, 0);
        } else if (n == 0) {
          ev.events = EPOLLIN;
          ev.data.fd = clientfd;

          epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
          close(clientfd);
        }
      }
    }
  }
  close(listenfd);
  return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 实现TCP服务端(select、poll、epoll) 的相关文章

  • 是否可以通过 TCP 连接到正在侦听 3G 网络端口的 iPhone?

    我正在开发一个严重依赖 P2P 的应用程序 但我目前没有任何 SIM 卡可供实验 因此我正在 wifi 网络上进行测试 我想知道 3G 网络上的 iPhone 是否可以连接以及是否需要穿越 NAT 设备 您位于提供商的路由器后面 您的 IP
  • 将一项选择中的两项计数相除

    我有一个这样的表 date timestamp Error integer someOtherColumns 我有一个查询来选择特定日期的所有行 SELECT from table WHERE date date 2010 01 17 现在
  • 如何根据多个字段选择不同的行

    我有一个表 其中包含 MSSQL 数据库中一系列事件的数据 ID Name Date Location Owner 1 Seminar Name 1 2013 08 08 A Location Name
  • 在 Perl 中如何接受多个 TCP 连接?

    我对 Linux 的 Perl 脚本有疑问 它的主要目的是成为 3 个应用程序之间的中间人 它应该做什么 它应该能够等待 UDP 文本 不带空格 udp port 当它收到 UDP 文本时 它应该将其转发到连接的 TCP 客户端 问题是我的
  • 为什么 peewee 将“id”列包含到 mysql select 查询中?

    我正在尝试学习如何将 peewee 与 mysql 一起使用 我在 mysql 服务器上有一个现有数据库和一个现有表 该表当前为空 我现在正在测试 gt gt gt db MySQLDatabase nhl user root passwd
  • MySQL 错误:#1142 - SELECT 命令被拒绝给用户

    我在一台服务器上的某个查询时遇到问题 在我测试过的所有其他地方 它工作得很好 但在我想使用它的服务器上 它不起作用 这是关于以下 SQL SELECT facturen id AS fid projecten id AS pid titel
  • 确定用winsock(FIONWRITE)可以发送多少字节?

    通过 select 我可以确定是否可以在不阻塞的情况下接收或发送任何字节 通过这个函数 我可以确定可以接收多少字节 function BytesAvailable S TSocket Integer begin if ioctlsocket
  • MySQL ORDER BY rand(),名称 ASC

    我想获取一个包含 1000 个用户的数据库并随机选择 20 个用户 ORDER BY rand LIMIT 20 然后按名称对结果集进行排序 我想出了以下查询not像我希望的那样工作 SELECT FROM users WHERE 1 OR
  • SQL select通常是如何实现的

    我有两节课 class PopulationMember public void operationOnThisMember1 void operationOnThisMember2 private Population populalti
  • Python套接字模块:Recv()数据响应被切断

    解释 我目前正在尝试使用 python 脚本控制智能电源板 为了实现这一点 我使用了带有套接字模块的 TCP 连接 大约 75 的情况下 我会得到我正在寻找的响应 数据 并且一切都运行良好 然而 大约 25 的情况下 响应会以完全相同的长度
  • C# Socket.receive连续接收0字节且循环中不阻塞

    我正在尝试用 C 编写一个最简单的多线程 TCP 服务器 它接收来自多个客户端的数据 每次连接新客户端时 都会建立套接字连接 并将套接字作为参数传递给新类函数 之后运行 while 循环并接收数据 直到客户端连接为止 这里的问题是 sock
  • 如何在Linux中打开端口[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我已经安装了 Web 应用程序 该应用程序在 RHEL centOS 上的端口 8080 上运行 我只能通过命令行访问该机器 我尝试从我的
  • 视频流上的 TCP 与 UDP

    我刚从网络编程考试回来 他们问我们的问题之一是 如果您要传输视频 您会使用 TCP 还是 UDP 请解释一下存储视频和实时视频流 对于这个问题 他们只是希望得到一个简短的答案 TCP 用于存储视频 UDP 用于实时视频 但我在回家的路上想到
  • 如何解决postgresql中group by和聚合函数的问题

    我正在尝试编写一个查询来划分两个 SQL 语句 但它显示了我 ERROR column temp missed must appear in the GROUP BY clause or be used in an aggregate fu
  • 自动打开命名管道和 tcp\ip

    我正在安装一个需要修改 SQL Server 的新产品 具体来说 启用 tcp ip 并打开命名管道 我知道如何手动完成 我想要的是一种通过 SQL 或 C 代码为新客户自动化执行此操作的方法 我希望有任何关于正确方向的建议 您可以使用 C
  • 简单的跨平台 TCP IP API?

    我不打算使用像 QT 或 wxWidgets 的 API 这样的大东西 我只想要可以在 Android iOS Windows Mac Linux 上运行的简单套接字 我正在制作一个事件驱动的纸牌游戏 所以 TCP 是最好的 本质上 我只想
  • 为什么 TCP 段中的 SYN 或 FIN 位会占用序列号空间中​​的一个字节?

    我试图理解这种设计背后的基本原理 我浏览了一些 RFC 但没有发现任何明显的东西 这并不是特别微妙 这样 SYN 和 FIN 位本身就可以被确认 因此如果丢失则可以重新发送 例如 如果连接关闭而没有发送更多数据 那么如果 FIN 没有发送任
  • VB SQL 语句未选择正确的行

    我试图使用 SELECT 语句在我的数据库中 选择 一个人 但它没有选择正确的人 我也不确定为什么 我正在使用访问数据库 数据库连接代码 Imports System Data OleDb Module Database Connectio
  • 序列化是通过套接字发送数据的最佳选择吗?

    有人告诉我 序列化不是通过套接字发送数据的最佳方法 但他们说他们在一本书上读过一次 并且不确定更好的方法 因为他们以前没有真正做过网络 那么序列化是最好的方法还是有更好的方法 如果这有很大的不同的话 这也是一个游戏 通过搜索有关通过它发送对
  • 每行中非空列的计数

    我有一个包含 4 列的表 在第 5 列中我想存储前 4 列中有多少个非空列的计数 例如 其中 X 是任意值 Column1 Column2 Column3 Column4 Count X X NULL X 3 NULL NULL X X 2

随机推荐

  • 有意思的题:(++a * a++)、(b++ * ++b)、(c++ * c++)、(++d * ++d)

    include lt stdio h gt int main int a 61 3 b 61 3 c 61 3 d 61 3 int a1 b1 c1 d1 a1 61 43 43 a a 43 43 b1 61 b 43 43 43 43
  • 详解LVDS通信协议

    目录 LVDS概述LVDS接口电路的组成LVDS输出接口电路类型单路6位LVDS输出接口双路6位LVDS输出接口单路8位1TL输出接口双路8位1TL输出位接口 典型LVDS发送芯片介绍四通道LVDS发送芯片五通道LVDS发送芯片十通道LVD
  • 自动跟随机器人:一种简易的自动跟随方案,自动跟随小车、自动跟随平衡小车、STM32、基于超声波的自动跟随小车

    目的 xff1a 一种廉价的跟随方案 xff0c 让大家都能够参与进来 xff0c 技术难度不大 xff0c 一些人也能够DIY一些属于自己的 跟随 机器人 xff01 并不是要做工业应用什么的 只是做出来玩玩 1 介绍 先看视频 xff0
  • 详解MIPI协议

    目录 前言MIPI简介MIPI联盟的MIPI DSI规范MIPI名词解释MIPI DSI分层结构command和video模式 D PHYLane模组Lane 全局架构Lane电压和状态DATA LANE操作模式时钟LANE低功耗状态高速数
  • 音频处理——详解PCM数据格式

    目录 知识储备什么是PCM采样采样率重采样 量化编码PCM常用指标 PCM数据流 知识储备 音频处理 音频编码原理简介 音频处理 音频处理的基本概念 什么是PCM PCM全称Pulse Code Modulation xff0c 翻译一下是
  • 音频处理——常用音频编码格式简介(PCM、G726、ADPCM、LPCM、G711、AAC)

    目录 PCMG726ADPCMLPCMG711AAC格式对比音频帧长音频播放过程 PCM 音频处理 详解PCM数据格式 音频处理 解析PCM格式实例 xff08 音量调控 xff09 G726 G 726是ITU T定义的音频编码算法 19
  • 音频处理——G711标准详解

    目录 G711简介G711A算法原理压缩方法举例代码 G711U算法原理压缩方法举例代码 G711A与G711U对比 参考链接 G711简介 G711是国际电信联盟ITU T定制出来的一套语音压缩标准 xff0c 它代表了对数PCM xff
  • PS流详解(载荷H264)

    目录 PS简介标准结构标准H264流结构定长音频帧和其他流式私有数据的结构 PS流封装标准PSH结构PES包结构PSM包结构体 元素流 PS 封装规则H264元素流封装规则音频元素流封装规则私有信息封装规则 PS简介 PS 封装方式需要支持
  • Postman中的authorization

    1 概述 Authorization是验证是否拥有从服务器访问所需数据的权限 当发送请求时 xff0c 通常必须包含参数 xff0c 以确保请求具有访问和返回所需数据的权限 Postman提供了授权类型 xff0c 可以轻松地在Postma
  • 操作pdf,提示startxref not found

    startxref not found多半是文件被损坏了 xff0c 检查一下 xff0c 是不是之前自己写的代码把pdf文件跑崩了 可以尝试重新生成一遍该pdf文件 xff0c 然后再进行操作 或者尝试一下 xff1a https www
  • FTP 530未登录

    提供一种思路 xff1a 如果说FTP服务器已开 xff0c 服务器也能ping通 就得考虑是不是我们在FTP服务器上设置的默认路径有问题 xff08 不符合我们的需求 xff09 Windows10下 xff0c FTP设置默认位置 xf
  • 开源个小demo

    https github com UnderADome epms 内部项目管理
  • LDAP的基本知识

    https zhuanlan zhihu com p 147768058 https www cnblogs com gaoyanbing p 13967860 html
  • 「权威发布」2019年电赛最全各类题目细节问题解答汇总

    点击上方 大鱼机器人 xff0c 选择 置顶 星标公众号 福利干货 xff0c 第一时间送达 xff01 各位朋友大家上午好 xff0c 今天是比赛的第二天 xff0c 许多朋友都给我发消息 xff0c 我不是不回 xff0c 我实在是回不
  • Unable to find explicit activity class

    做项目从一个activity逐渐转向到使用多个activity xff0c 这个时候新手就容易出现一个问题 xff0c 忘了给activity在AndroidManifest xml中注册 打开日志 xff0c 在遇到这个报错信息的时候 x
  • Errors running builder 'Maven Project Builder'

    由于第一次玩maven的时候 xff0c 很多东西都还是懵懵懂懂 xff0c 不是很清楚 xff0c 不知道怎么把Myeclipse中的maven配置弄坏了 xff0c 从外部导入maven项目的时候 xff0c 总会报一些错误 xff1a
  • Type handler was null on parameter mapping for property '__frch_id_0'

    1 Type handler was null on parameter mapping for property frch id 0 2 Type handler was null on parameter mapping or prop
  • 如何解决error: failed to push some refs to 'xxx(远程库)'

    在使用git 对源代码进行push到gitHub时可能会出错 xff0c 信息如下 此时很多人会尝试下面的命令把当前分支代码上传到master分支上 git push u origin master 但依然没能解决问题 出现错误的主要原因是
  • expected an indented block

    Python中没有分号 xff0c 用严格的缩进来表示上下级从属关系 导致excepted an indented block这个错误的原因一般有两个 xff1a 1 冒号后面是要写上一定的内容的 xff08 新手容易遗忘这一点 xff09
  • C 实现TCP服务端(select、poll、epoll)

    使用C简单的实现一个tcp server xff0c 包括常规server 多线程实现server select实现server poll实现server epoll实现server IO模型原理可以看上一篇文章 常规模式 define M