Linux网络编程:Select

#include <asm-generic/socket.h>
#include <cctype>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <netinet/in.h>
#include <strings.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "sock_wrapper.h"

const static uint16_t kPort = 4433;
const static char *kIpStr = "192.168.3.20";

int main() {

  char buffer[BUFSIZ];

  int listenFd = socket(AF_INET, SOCK_STREAM, 0);

  int reuse = 1;
  setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (const void *)&reuse, sizeof(reuse));

  sockaddr_in addr;
  bzero(&addr, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(kPort);
  inet_pton(AF_INET, kIpStr, &addr.sin_addr);

  int ret = bind(listenFd, (const struct sockaddr *)&addr, sizeof(addr));
  if (ret < 0) {
    perror("bind error.\n");
    return -1;
  }

  //设置最同时监听上限
  ret = listen(listenFd, 125);
  if (ret < 0) {
    perror("list error.\n");
    return -1;
  }

  //在linux上是一个大小为1024的bit数组,大小由FD_SETSIZE决定
  fd_set all_set;

  //可以理解成对刚分配的all_set内存进行初始化操作
  //这一步是必须的,否则可能出现内存问题
  FD_ZERO(&all_set);
  //将对应的文件描述符,加入到set中
  FD_SET(listenFd, &all_set);

  int maxFd = listenFd;

  while (1) {
    fd_set r_set = all_set;
    //第一个参数是监听的三个文件描述符集合的最大文件描述符 +1
    //第二个参数是一个传入传出参数:传入:要监听读取事件的文件描述符表,传出:有读取事件发生的文件描述符
    //其他的分别是写入事件,异常事件,没有的话可以传空
    //最后一个参数:表示阻塞等待的时间,如果为NULL表示一直阻塞,他是一个指针类型
    //返回值表示:发生事件的全部文件描述符个数
    int selectNum = select(maxFd + 1, &r_set, nullptr, nullptr, NULL);
    if (selectNum < 0) {
      perror("select error\n");
      exit(-1);
    }

    //判断是否是监听socket上有读事件,如果是,则应该调用accept Api
    if (FD_ISSET(listenFd, &r_set)) {
      sockaddr_in clientAddr;
      bzero(&clientAddr, sizeof(clientAddr));
      socklen_t clientLen = sizeof(clientAddr);
      int connFd = accept(listenFd, (struct sockaddr *)&addr, &clientLen);
      if (connFd < 0) {
        perror("accept error\n");
        exit(0);
      }
      //将新接入联通的文件描述符加入到监听观察集合中
      FD_SET(connFd, &all_set);
      //检测更新最大文件描述符
      if (maxFd < connFd) {
        maxFd = connFd;
      }
      //表示只有一个文件描述符上有事件发生,并且这个事件赢被处理,因此不需要在后续的处理
      if (selectNum == 1) {
        continue;
      }
    }

    //客户端连接文件描述符上存在事件发生,则循环遍历所以监听的文件描述符
    for (int connFd = listenFd + 1; connFd < maxFd + 1; ++connFd) {
      if (FD_ISSET(connFd, &r_set)) {
        int readNum = read(connFd, (void *)buffer, sizeof(buffer));
        if (readNum < 0) {
          perror("read_bytes error.");
          exit(-1);
        }

        //读取的数为0时,表示对端socket关闭了
        if (readNum == 0) {
          //这里有个问题,当connFd关闭时,如果是当前最大文件描述符,则没有更新最大文件描述符
          close(connFd);
          //将文件描述符从set中移除
          FD_CLR(connFd, &all_set);
          printf("close client \n");
          break;
        }

        //处理数据
        printf("server receive: %s\n",buffer);
        for (int i = 0; i < readNum; ++i) {
          buffer[i] = toupper(buffer[i]);
        }

        //结果会写给对端
        int writeNum = write(connFd, buffer, readNum);
        if (writeNum < 0) {
          perror("write error");
          exit(-1);
        } else {
          printf("server response success.\n");
        }
      }
    }
  }
  close(listenFd);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值