使用select函数实现TCP并发服务器

2023-05-16

首先介绍一下select 函数的功能、参数、返回值。

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set);  //将某个文件描述符从监视表中移除
int  FD_ISSET(int fd, fd_set *set);//判断文件描述符是否准备就绪
void FD_SET(int fd, fd_set *set);//将文件描述符放入监视表中
void FD_ZERO(fd_set *set);    //清空监视表

 select 函数监控文件描述符的状态,当某一个或几个文件描述符准备就绪,则可以执行相应的I/O操作。这个函数最多可以监视1024个文件描述符。

参数:

        nfds:这个参数就是程序所监视的最大的文件描述符+1。(置于为什么要加一,是由于内核中的代码在写的时候就是这样设定的,比如for循环,for(i=1;i<10;i++),i<10的时候是循环9次,i<=10的时候,循环10次,内核中设计这个函数的时候估计就是差了一个等号)。

        readfds:这个参数是select 函数监视的读文件描述符的集合。如果不监视传NULL

        writefds:这个参数是select 函数监视的写文件描述符的集合。如果不监视传NULL

        exceptfds:这个参数是select 函数监视的异常文件描述符的集合。如果不监视传NULL

        timeout: 设置函数的超时时间

基于select 函数实现的TCP服务器的基本思路就是,每次有客户端连接的时候,将accetp 返回的文件描述符放入被监视的文件描述符集合中去,当客户端发信息的时候,对应的文件描述符准备就绪就执行相应的操作。当客户端离开或者断开连接,就将文件描述符从集合中删除。

接下来直接上代码。上面没有叙述的部分会在代码中以注释的方式讲解。

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <unistd.h>
#define ERRLOG(msg) do{\
        printf("file:%s func:%s  line:%d\n",__FILE__,__func__,__LINE__);\
        perror(msg);\
        exit(-1);\
                }while(0)
int main(int argc, const char *argv[])
{
    int clientfd;//客户端连接后产生的文件描述符
    int sockfd;
    if(-1 == (sockfd=socket(AF_INET,SOCK_STREAM,0)))//创建流式套接字
        ERRLOG("socket error");
    struct sockaddr_in serveraddr;
    memset(&serveraddr,0,sizeof(serveraddr));
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(atoi(argv[2]));
    socklen_t serveraddr_len=sizeof(serveraddr);//填充服务器网络信息结构体
    if(-1 == bind(sockfd,(struct sockaddr *)&serveraddr,serveraddr_len))//将套接字和网络信息结构体绑定
        ERRLOG("bind error");
    if(-1 == listen(sockfd,5))//将套接字设置为被监听状态
        ERRLOG("listen error");
    fd_set readfds;
    fd_set writefds;
    fd_set exceptfds;//创建文件描述符监视表
    fd_set readfds_temp;
    fd_set writefds_temp;
    fd_set exceptfds_temp;//创建文件描述符监视表副本,因为每次有文件描述符准备就绪号之后,select会将表中没有准备就绪的文件描述符清除
    FD_ZERO(&readfds_temp);
    int maxfd=0;
    FD_ZERO(&readfds);
    FD_SET(sockfd,&readfds);
    int i=0;
    int ret=0;
    maxfd=maxfd>sockfd?maxfd:sockfd;
    readfds_temp=readfds;
    int nbytes;
    char buf[128]={0};
    while(1){
        readfds_temp=readfds;
        if(-1 == (ret = select(maxfd+1,&readfds_temp,NULL,NULL,NULL))){
            ERRLOG("select error");
        }else{
            for(i=3;i<maxfd+1&&ret!=0;i++){//select 的返回值表示准备就绪的文件描述符的个数
                if(FD_ISSET(i,&readfds_temp)){
                    if(i == sockfd){//如果准备就绪的文件描述符是sockfd,则说明有新的用户过来连接
                        if(-1 == (clientfd = accept(sockfd,NULL,NULL)))
                            ERRLOG("accept error");
                        FD_SET(clientfd,&readfds);
                        maxfd=maxfd>clientfd?maxfd:clientfd;//每次有新的文件描述符加入就更新最大的文件描述符
                        printf("client[%d] link...\n",clientfd);
                    }else{//说明有人发消息
                        memset(buf,0,sizeof(buf));
                        if(-1 == (nbytes = recv(i,buf,sizeof(buf),0))){
                            ERRLOG("recv error");
                        }else if(nbytes == 0){
                            printf("client[%d] disconnect...\n",i);
                            FD_CLR(i,&readfds);
                            continue; 
                        }
                        printf("do work...");//根据代码要实现的功能填写代码
                        strcpy(buf,"completed!!");
                        send(i,buf,sizeof(buf),0);
                    }
                    ret--;//每一次执行完操作就将准备就绪的文件描述符的个数减1
                }
                
            }
            
        }
    }
    
    
    /*your code*/
    return 0;
}

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

使用select函数实现TCP并发服务器 的相关文章

随机推荐

  • 我的首篇博客——记录学习,不忘初心

    Hello 大家好 xff01 我是阿冰 xff01 今天是2022年12月2日 xff0c 受疫情影响 xff0c 我们学校的同学都早早的回家了 xff0c 今天就是我回家的第五天 其实 xff0c 这并不算是真正意义的寒假 xff0c
  • Java标识符和关键字

    目录 前言 一 关键字 1 什么是关键字 xff1f 2 关键字的一些注意事项 二 标识符 1 什么是标识符 xff1f 2 标识符书写规范 总结 前言 在华清学习的所思所想 xff1a Java关键字及标识符 一 关键字 1 什么是关键字
  • 图为科技NVIDIA Jetson Xavier NX测评

    NVIDIA推出了世界上最小的人工智能计算机 NVIDIA Jetson Xavier NX 整个设置的大小小于普通大小的借记卡或信用卡 该模块虽然不是业务中最小的 xff0c 但它所提供的处理能力和其他质量足以弥补其尺寸 Jetson N
  • Jetson TX2 NX 模块以纳米尺寸提供 TX2 电源

    Nvidia 推出了Jetson TX2计算模块 的降速功能 xff0c 该模块位于 TX2 和低端Jetson Nano之间 Jetson TX2 NX 在与 TX2 相同的六核 CPU 和 256 核 Pascal GPU 上运行 Li
  • 无人机在行业的应用方面呈现出多元化的趋势

    随着科技的不断发展和进步 xff0c 无人机的行业应用也逐渐扩大 作为民用无人机主要细分领域之一 xff0c 测绘无人机的发展也越来越成熟 xff0c 市场规模保持高速增长 无人机在应用方面也呈现出多元化的趋势 xff0c 备受各个行业用户
  • 嵌入式能从事什么职业?

    嵌入式本身发展是很好的 xff0c 这也是大家接触它的原因 xff0c 最后大家也是想通过学习嵌入式而找到关于嵌入式开发的工作 xff0c 想必大家也应该知道嵌入式工作要求有很多 xff0c 下面就一起来看看嵌入式能从事什么职业吧 点击获取
  • 嵌入式入门学习的必要步骤

    很多新手在入门嵌入式的时候 xff0c 经常会有很多问题 xff0c 这也都是想要多多去了解嵌入式 xff0c 也害怕自己浪费了时间还没有学会嵌入式 xff0c 掌握到好方法学习嵌入式 xff0c 那么就会事半功倍 xff0c 下面一起来看
  • 逆变器原理

    逆变器是把直流电转变为交流电的一种装置 它一般包括逆变桥 控制逻辑和滤波电路组成 主要是把各种直流源转变为交流供交流负载使用 xff0c 一般直流源有蓄电池 干电池 太阳能电池等 xff0c 可以应用到不间断电源 UPS 太阳能发电转换等
  • RS-485 通讯协议简介

    与 CAN 类似 xff0c RS 485 是一种工业控制环境中常用的通讯协议 xff0c 它具有抗干扰能力强 传输距离远的特点 RS 485 通讯协议由 RS 232协议改进而来 xff0c 协议层不变 xff0c 只是改进了物理层 xf
  • 反向散射耦合RFID系统的原理及特点,带你更深入的了解

    一 反向散射耦合RFID系统 1 反向散射 雷达技术为RFID的反向散射耦合方式提供了理论和应用基础 当电磁波遇到空间目标时 xff0c 其能量的一部分被目标吸收 xff0c 另一部分以不同的强度散射到各个方向 在散射的能量中 xff0c
  • 西门子PLC,1200PLC如何接线,2分钟就能明白

    西门子PLC xff0c 1200PLC如何接线 xff0c 2分钟就能明白 西门子PLC xff0c 1200PLC如何接线 xff0c 2分钟就能明白 哔哩哔哩 bilibili
  • 2022年嵌入式开发就业前景怎么样?

    时间 xff1a 2022年5月26号 xff01 这几年嵌入式开发的发展前景可以说是非常的香 xff01 从工资和找工作的难易程度上说都是 xff01 按老师傅的说法就是 xff1a 加班不严重 xff0c 注重积累 xff0c 越往底层
  • ARM结构体系3:ARM指令的寻址和异常中断处理

    目录 ARM处理器的八种寻址方式 1 立即数寻址 2 寄存器寻址 3 寄存器间接寻址 4 寄存器移位寻址 5 基址变址寻址 6 多寄存器寻址 7 相对寻址 8 堆栈寻址 9 GNU汇编伪指令 异常中断处理 1 7种异常源 2 异常向量表 A
  • 51单片机(ESP8266模块)

    前言 xff1a 蓝牙 xff0c ESP 01s xff0c Zigbee NB Iot等通信模块都是基于AT指令的设计 一 AT指令 AT指令集是从终端设备 xff08 Terminal Equipment xff0c TE 或数据终端
  • 嵌入式工作机会会越来越少吗

    我认为嵌入式工作会越来越多 在当前产业结构升级的大背景下 xff0c 物联网会与诸多的行业领域产生更加紧密的联系 xff0c 而这个过程必然离不开嵌入式开发的参与 应用场景对于嵌入式开发领域的发展有非常直接的影响 xff0c 嵌入式开发要想
  • 大学生为何很想往嵌入式方向发展?

    这几年嵌入式工资一直在再涨 xff0c 挺好的 xff01 可以选择的公司也比较多 xff0c 起薪差不读在10k 13k的样子 招聘公司统计的数据是19K 优点1 xff1a 应届生嵌入式行业的薪资在毕业生眼里看来真的是很香 xff0c
  • 涨姿势 | 一文说透电机控制器硬件在环测试(MCU HIL)

    软件质量是嵌入式产品开发中最关注的问题之一 随着产品迭代 xff0c 软件复杂程度越来越高 xff0c 为保证软件质量 xff0c 需要对软件进行大量的测试 xff0c 这会在整个产品周期中消耗大量时间及资源 另一方面 xff0c 市场竞争
  • VMware Workstation创建Windows 11(21H2)虚拟机

    2021年6月24日 xff0c 微软发布了Windows 11 xff0c 很多人都想 尝尝鲜 可以为较高的电脑配置 xff0c 使得很多老电脑 望而却步 xff0c 或者有人想换可又嫌麻烦或不舍得 所以今天我来带大家创建Windows
  • 计算机知识——常见的存储类型

    一 常见存储器类型 xff1a 1 易失 非易失性存储器 xff1a 是指存储器断电后 xff0c 它存储的数据内容是否会丢失的特性 由于一般易失性存储器存取速度快 xff0c 而非易失性存储器可长期保存数据 易失性存储器最典型的代表是内存
  • 使用select函数实现TCP并发服务器

    首先介绍一下select 函数的功能 参数 返回值 int select int nfds fd set readfds fd set writefds fd set exceptfds struct timeval timeout voi