10.1 今日任务:select实现服务器并发

news2024/12/23 20:36:13
#include <myhead.h>

#define ERR_MSG(msg)  do{\
    fprintf(stderr, "__%d__:", __LINE__); \
    perror(msg);\
}while(0)

#define PORT 8888               //端口号,范围1024~49151
#define IP  "192.168.112.115"   //本机IP,ifconfig


int keybord_events(fd_set readfds);
int cliConnect_events(int, struct sockaddr_in*, fd_set *, int *);
int cliRcvSnd_events(int, struct sockaddr_in*, fd_set *, int* );

int main(int argc, const char *argv[])
{
    //创建流式套接字 socket
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sfd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("socket create success sfd=%d\n", sfd);

    //允许端口快速的被复用
    int reuse = 1;
    if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }
    printf("允许端口快速的被复用成功\n");


    //填充地址信息结构体给bind函数绑定,
    //真实的地址信息结构体根据地址族指定 AF_INET:man 7 ip
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;      //必须填AF_INET;
    sin.sin_port        = htons(PORT);  //端口号的网络字节序
    sin.sin_addr.s_addr = inet_addr(IP);//本机IP


    //绑定服务器的地址信息---> 必须绑定 bind
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("bind");
        return -1;
    }
    printf("bind success\n");


    //将套接字设置为被动监听状态 listen
    if(listen(sfd, 128) < 0)
    {
        ERR_MSG("listen");
        return -1;
    }
    printf("listen success\n");

    //创建一个读集合
    fd_set readfds, tempfds;

    //fd_set 本质上是一个结构体,结构体中有一个整形数组。
    //若不清空,则会存有随机值,可能会随机到有效的,但是不需要监测的文件描述符
    //清空集合
    FD_ZERO(&readfds);

    //将需要监测的文件描述符添加到集合中
    FD_SET(0, &readfds);
    FD_SET(sfd, &readfds);

    int maxfd = sfd;                    //存储最大的文件描述符

    int s_res = -1;
    ssize_t res = -1;
    char buf[128] = "";
    struct sockaddr_in saveCin[1024];   //备份连接成功的客户端的地址信息,用下标来对应文件描述符


    while(1)
    {
        tempfds = readfds;
        //执行IO多路复用函数
        s_res = select(maxfd+1, &tempfds, NULL, NULL, NULL);
        if(s_res < 0)
        {
            ERR_MSG("select");
            return -1;
        }
        else if(0 == s_res)
        {
            printf("time out,,\n");
            break;
        }

        printf("__%d__\n", __LINE__);
        //能运行到当前位置,则代表select函数解除阻塞,即代表集合中有文件描述符准备就绪
        //此时集合中会只剩下产生事件的文件描述符,例如:
        //0号准备就绪,则集合中会只剩下0号
        //sfd准备就绪,则集合中会只剩下sfd
        //0和sfd均准备就绪,则集合中会剩下0和sfd;
        //只需要判断集合中剩下哪个文件描述符,走对应处理函数即可;

        for(int i=0; i<=maxfd; i++)
        {
            if(FD_ISSET(i, &tempfds) == 0)
                continue;

            //能运行到当前位置,则说明i所代表的文件描述符在集合中
            if(0 == i)          //0在集合中
            {
                printf("触发键盘输入事件\n");
                keybord_events(readfds);
            }
            else if(sfd == i)       //sfd在集合中
            {
                printf("触发客户端连接事件\n");
                cliConnect_events(sfd, saveCin, &readfds, &maxfd);
            }
            else
            {
                printf("触发客户端交互事件\n");
                cliRcvSnd_events(i, saveCin, &readfds, &maxfd);
            }
        }

    }


    if(close(sfd) < 0)
    {
        ERR_MSG("close");
        return -1;
    }

    return 0;
}

//键盘输入事件
int keybord_events(fd_set readfds)
{
    char buf[128] = "";
    int sndfd = -1;             //从终端获取一个文件描述符,发送数据给该文件描述符对应的客户端
    bzero(buf, sizeof(buf));

    int res = scanf("%d %s", &sndfd, buf);
    while(getchar() != 10);
    if(res != 2)                //终端输入的数据格式错误
    {
        printf("输入数据的格式错误,:fd string\n");
        return -1;                                                                                                          
    }

    if(sndfd<=2 || FD_ISSET(sndfd, &readfds)==0)        //判断文件描述符的合法性
    {
        printf("非法的文件描述符:sndfd=%d\n", sndfd);
        return -1;
    }

    if(send(sndfd, buf, sizeof(buf), 0) < 0)
    {
        ERR_MSG("send");
        return -1;
    }
    printf("send success\n");


    return 0;
}

//客户端连接事件
int cliConnect_events(int sfd, struct sockaddr_in saveCin[], fd_set *preadfds, int *pmaxfd)
{
    int newfd = -1;
    struct sockaddr_in cin;             //存储客户端的地址信息
    socklen_t addrlen = sizeof(cin);    //真实的地址信息结构体的大小

    newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
    if(newfd < 0)
    {
        ERR_MSG("newfd");
        return -1;
    }
    printf("[%s:%d]客户端连接成功 newfd=%d\n", \
            inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
    saveCin[newfd] = cin;                       //将cin另存到newfd对应的下标位置去

    FD_SET(newfd, preadfds);                    //将newfd添加到集合中
    *pmaxfd = *pmaxfd>newfd ? *pmaxfd:newfd;    //更新maxfd

    return 0;
}

//客户端交互事件
int cliRcvSnd_events(int fd, struct sockaddr_in* saveCin, fd_set *preadfds, int* pmaxfd)
{
    char buf[128] = "";
    //清空字符串
    bzero(buf, sizeof(buf));    //memset

    //接收
    ssize_t res = recv(fd, buf, sizeof(buf), 0);
    if(res < 0)
    {
        ERR_MSG("recv");
        return -1;
    }
    else if(0 == res)
    {
        printf("[%s:%d]客户端下线 newfd=%d\n", \
                inet_ntoa(saveCin[fd].sin_addr), ntohs(saveCin[fd].sin_port), fd);

        close(fd);              //关闭文件描述符
        FD_CLR(fd, preadfds);   //将文件描述符从集合中剔除

        //由于剔除的文件描述符可能是最大文件描述符,所以要更新maxfd 
        //从大往小判断,若在集合中,则该文件描述符就是最大的文件描述符
        /*
           for(; *pmaxfd>=0; *pmaxfd--)
           {
           if(FD_ISSET(*pmaxfd, preadfds))
           break;
           }
           */

        while(FD_ISSET(*pmaxfd, preadfds)==0 && (*pmaxfd)-->=0);
        return 0;

    }
    printf("[%s:%d] newfd=%d : %s\n", \
            inet_ntoa(saveCin[fd].sin_addr), ntohs(saveCin[fd].sin_port), fd, buf);

    //发送
    strcat(buf, "*_*");
    if(send(fd, buf, sizeof(buf), 0) < 0)
    {
        ERR_MSG("send");
        return -1;
    }
    printf("send success\n");

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1054596.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Linux] 4.常用初级指令

pwd&#xff1a;显示当前文件路径 ls:列出当前文件夹下有哪些文件 mkdir空格文件名&#xff1a;创建一个新的文件夹 cd空格文件夹名&#xff1a;进入文件夹 cd..&#xff1a;退到上一层文件夹 ls -a&#xff1a;把所有文件夹列出来 .代表当前文件夹 ..代表上层文件夹 用…

第 365 场 LeetCode 周赛题解

A 有序三元组中的最大值 I 参考 B B B 题做法… class Solution { public:using ll long long;long long maximumTripletValue(vector<int> &nums) {int n nums.size();vector<int> suf(n);partial_sum(nums.rbegin(), nums.rend(), suf.rbegin(), [](int x…

Facebook Delos 中的虚拟共识协议

背景 Facebook 的软件系统栈一般包括两层&#xff1a;上层是数据平面&#xff0c; 下层是控制平面。 facebook software stack 数据平面包括大量的服务&#xff0c;他们需要存储和处理海量数据。控制平面用来支撑数据平面&#xff0c;起到一些控制作用&#xff1a;调度、配置…

XSS-labs

XSS常见的触发标签_xss标签_H3rmesk1t的博客-CSDN博客 该补习补习xss漏洞了 漏洞原理 网站存在 静态 和 动态 网站 xss 针对的网站 就是 动态网站 动态网站会根据 用户的环境 与 需求 反馈出 不同的响应静态页面 代码写死了 只会存在代码中有的内容 通过动态网站 用户体…

2023年中国火化设备行业现状分析:随着城市化进程的推进,市场需求将持续增长[图]

火化设备行业是指生产和提供用于尸体火化处理的设备和相关服务的行业。火化设备主要用于将尸体进行高温焚烧&#xff0c;将尸体转化为骨灰&#xff0c;以达到尸体处理和殡葬的目的。 火化设备行业优点 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 我国火…

C++面试八股(一)

目录 C和C的区别 1、语言特性 2、内存管理 3、C的库更加丰富 4、对异常的处理 什么是封装继承多态&#xff1f; 封装 继承 多态 new和malloc的区别 STL容器有哪些&#xff1f;容器对应的使用场景&#xff1f;&#xff08;挑一个你认为最熟悉的容器&#xff09; vector、…

评估指标Pre\Rec\F1\AUC

AUC的计算方法同时考虑了分类器对于正例和负例的分类能力&#xff0c;在样本不平衡的情况下&#xff0c;依然能够对分类器作出合理的评价。AUC代表模型预估样本之间的排序关系&#xff0c;即正负样本之间预测的gap越大&#xff0c;auc越大. 来自 https://blog.csdn.net/pearl8…

wustctf2020_name_your_cat

wustctf2020_name_your_cat Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)32位&#xff0c;开了NX和canary int shell() {return system("/bin/sh"); }有个后门函数 unsigned int…

AutoHotkey ---- 统一所有软件的快捷键(分析篇)

文章目录 引言理论编程方案 引言 快捷键大家都不陌生.但是目前的快捷键普遍存在以下几个问题。 不统一,即word、ppt、浏览器、各种编辑器、邮件客户端等等&#xff0c;都有属于自己的一套快捷键。快捷键冲突&#xff0c;即不同软件使用了相同的快捷键&#xff0c;而且作用域是…

GNN PyG~torch_geometric 学习理解

目录 1. PyG Introduction 2. PyG Installation 2.1 PyG 安装常见错误及原因 2.2 PyG 具体安装步骤 3. torch_geometric packages torch_geometric.data.Data Dataset 与 DataLoader Dropout、BatchNorm 3. torch_geometric: 理解edge_index 3.1 理解 mini-batch edg…

[H5动画制作系列]帧代码运行顺序测试

刚开始接触Animate CC(过去叫:Flash),对于帧代码的执行顺序十分迷惑。所以,专门做一个简单代码顺序测试. 准备工作: 代码图层actions,第1帧和第10帧为关键帧。 背景图层bg,就一个字符串红色Test.界面如下: 代码测试步骤: 第1帧参考代码如下: 第10帧参考代码如下: …

​68条萝卜刀《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书

​68条萝卜刀《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书 ​68条萝卜刀《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书

打包python模块代码到pypi

python中&#xff0c;我们会在自己业务中&#xff0c;重复性的使用某些功能。我们可以把这些公用的模块&#xff0c;打包上传&#xff0c;然后给需要的人使用&#xff0c;pypi给我们提供了这个机会 本期目录 一、准备工作 二、编写文件 三、上传下载 一、准备工作 1、需要git…

k8s实战案例之部署Nginx+Tomcat+NFS实现动静分离

1、基于镜像分层构建及自定义镜像运行Nginx及Java服务并基于NFS实现动静分离 1.1、业务镜像设计规划 根据业务的不同,我们可以导入官方基础镜像,在官方基础镜像的基础上自定义需要用的工具和环境,然后构建成自定义出自定义基础镜像,后续再基于自定义基础镜像,来构建不同服…

软件测试之Python基础学习

目录 一、Python基础 Python简介、环境搭建及包管理 Python简介 环境搭建 包管理 Python基本语法 缩进(Python有非常严格的要求) 一行多条语句 断行 注释 变量 基本数据类型(6种) 1. 数字Number 2. 字符串String 3. 列表List 4. 元组Tuple 序列相关操作方法 …

Unity 鼠标悬浮时文本滚动(Text Mesh Pro)

效果 直接将脚本挂载在Text Mesh Pro上&#xff0c;但是需要滚动的文本必须在Scroll View中&#xff0c;否侧会定位错误&#xff0c;还需要给Scroll View中看需求添加垂直或者水平布局的组件 代码 using System.Collections; using System.Collections.Generic; using UnityE…

【生物信息学】使用谱聚类(Spectral Clustering)算法进行聚类分析

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 3. IDE 三、实验内容 0. 导入必要的工具 1. 生成测试数据 2. 绘制初始数据分布图 3. 循环尝试不同的参数组合并计算聚类效果 4. 输出最佳参数组合 5. 绘制最佳聚类结果图 6. 代码整合 一、实验介绍…

【BLIP/BLIP2/InstructBLIP】一篇文章快速了解BLIP系列(附代码讲解说明)

文章目录 BLIP系列1. BLIP1.1 动机1.2 整体架构1.3 损失函数1.4 Captioning and Filtering(CapFilt)1.4.1 Why&#xff1f;1.4.2 方法 2. BLIP22.1 Q-Former的设计2.2 实现功能2.2.1 图像文本检索(Image-Text Retrieval)2.2.2 图像字幕(Image Captioning)2.2.3 视觉问答(VQA)2.…

1. Flink程序打Jar包

文章目录 步骤注意事项 步骤 用 maven 打 jar 包&#xff0c;需要在 pom.xml 文件中添加打包插件依赖 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><ver…

Python绘图系统24:绘图类型和坐标映射的关系

文章目录 类别与轴数坐标类别对映射的影像绘图类别对坐标轴的影响源代码 Python绘图系统&#xff1a; 前置源码&#xff1a; Python打造动态绘图系统&#x1f4c8;一 三维绘图系统 &#x1f4c8;二 多图绘制系统&#x1f4c8;三 坐 标 轴 定 制&#x1f4c8;四 定制绘图风格 &a…