IO多路转接之select(使用select实现TCP服务器)

本文介绍了如何利用select函数创建TCP服务器。讲解了select的函数原型、返回值、特点和缺点。select函数用于监控文件描述符的可读、可写和异常事件,通过fd_set数据结构和struct timeval进行时间控制。尽管select存在手动设置集合和文件描述符数量限制等缺点,但文章仍展示了如何在实践中应用select实现TCP服务器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

select

函数原型
#include<sys/select.h>
select(int nfds, fd_set *readfds, fd_set * writefds, fd_set *exceptfds, struct timeval *timeout);

  • nfds代表最大文件描述符值+1
  • readfds、writefds、exceptfds分别代表可读、可写、异常事件集合
  • timeout代表等待时间

timeout参数:

  • NULL:select阻塞等待
  • 0:仅检测文件描述符状态,然后立即返回
  • 特定值,如果在特定时间内没有事件发生,就会超时返回

fd_set:
在这里插入图片描述
在这里插入图片描述
fd_set代表位图,使用位图中对应的位来监控文件描述符,其接口如下:

void FD_CLR(int fd, fd_set *set);   // 用来清除描述词组set中相关fd 的位
int FD_ISSET(int fd, fd_set *set);  // 用来测试描述词组set中相关fd 的位是否为真
void FD_SET(int fd, fd_set *set);   // 用来设置描述词组set中相关fd的位
void FD_ZERO(fd_set *set);

struct timeval:

struct timeval 
{
   
   
    time_t         tv_sec;       //秒
    suseconds_t    tv_usec;    //毫秒
};
函数返回值
  • 执行成功,返回发生事件的文件描述符个数
  • 如果返回0代表在描述词状态改变前已超过timeout时间,没有返回
  • 发生错误时返回-1

错误值可能为:

  • EBADF 文件描述词为无效的或该文件已关闭
  • EINTR 此调用被信号所中断
  • EINVAL 参数n 为负值
  • ENOMEM 核心内存不足
select特点
  • 可监控的文件描述符个数取决与sizeof(fd_set)的值
  • 将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd
    • 一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断
    • 二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个参数
select缺点
  • 每次调用select, 都需要手动设置fd集合, 从接口使用角度来说也非常不便
  • 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
  • 同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
  • select支持的文件描述符数量太小
使用select实现TCP服务器

封装TCP类

#pragma once

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <iostream>
#include <string>

//流程:
//创建套接字
//绑定地址信息
//客户端---连接接口
//监听
//获取新连接
//发送数据
//接收数据
//关闭套接字

class TcpSrv
{
   
   
public:
    TcpSrv()
    {
   
   
        sockfd_ = -1;
    }
    ~TcpSrv()
    {
   
   }

    bool CreateSock()
    {
   
   
        sockfd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(sockfd_ < 0)
        {
   
   
            perror("socket");
            return false;
        }
        return true;
    }

    bool Bind(const std::string &ip, uint16_t port)
    {
   
   
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值