国庆作业 day 2

news2025/1/20 19:16:54

 select实现服务器并发

#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.0.103"   //本机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/1064144.html

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

相关文章

VUE3照本宣科——package.json与vite.config.js

VUE3照本宣科——package.json与vite.config.js VUE3照本宣科系列导航 前言一、package.json1.name2.version3.private4.scripts5.dependencies6.devDependencies 二、vite.config.js1.plugins2.resolve.alias3.base4.mode 三、VUE3照本宣科系列总结 VUE3照本宣科系列导航 1.VU…

ZRTP交叉编译与移植

1 ZRTP源码下载 这里采用的是libzrtp来自于freeswitch&#xff1a;libs/libzrtp。 2 ZRTP交叉编译 zrtp编译比较简单&#xff0c;采用configure进行编译在根目录心中zrtp编译脚本&#xff0c;只需要指定交叉编译工具链和安装地址即可。脚本如下所示&#xff1a; unset CC C…

文心一言 VS 讯飞星火 VS chatgpt (107)-- 算法导论10.1 5题

五、用go语言&#xff0c;栈插入和删除元素只能在同一端进行&#xff0c;队列的插入操作和删除操作分别在两端进行&#xff0c;与它们不同的&#xff0c;有一种双端队列(deque)&#xff0c;其插入和删除操作都可以在两端进行。写出4个时间均为 O(1)的过程&#xff0c;分别实现在…

Python之字符串分割替换移除

Python之字符串分割替换移除 分割 split(sepNone, maxsplit-1) -> list of strings 从左至右sep 指定分割字符串&#xff0c;缺省的情况下空白字符串作为分隔符maxsplit 指定分割的次数&#xff0c;-1 表示遍历整个字符串立即返回列表 rsplit(sepNone, maxsplit-1) -> …

【熬夜爆肝版】JAVA基础入门专栏——1.JAVA开发入门

JAVA开发入门 1、Java概述1&#xff09;起源2&#xff09;特点3&#xff09;应用领域 2、JDK1&#xff09;定义2&#xff09;作用3&#xff09;组成4&#xff09;JDK版本与兼容性5&#xff09;JDK的安装与配置6&#xff09;JDK的发行版 3、系统环境变量1&#xff09;定义2&…

【Java项目推荐之黑马头条】你的登录鉴权业务是怎么实现的?

前言 在学习Java的路上还是遇到了很多不错的好项目的&#xff0c;今天分享给大家&#xff0c;希望能对大家面试有所帮助&#xff01; 后续会继续推荐其他好的项目&#xff0c;这次推荐的是B站开源的视频黑马头条项目&#xff0c;来吧学会它一起去虐面试官&#xff01;&#x…

【C语言初阶】初识C语言

目录 一、什么是C语言 二、第一个C语言程序 三、数据类型 类型的使用&#xff1a; 四、变量、常量 4.1 定义变量的方法 4.2 变量的命名 4.3 变量的分类 4.4 变量的使用 4.5 变量的作用域和生命周期 4.5.1 作用域 4.5.2 生命周期 4.6 常量 五、字符串转义字符注释 …

【计算机组成 课程笔记】7.2 DRAM和SRAM

课程链接&#xff1a; 计算机组成_北京大学_中国大学MOOC(慕课) 7 - 2 - 702-DRAM和SRAM&#xff08;13-22--&#xff09;_哔哩哔哩_bilibili 从【计算机组成 课程笔记】7.1 存储层次结构概况_Elaine_Bao的博客-CSDN博客中&#xff0c;我们了解到&#xff1a;SRAM比较快&#x…

x64内核实验5-API进0环

x64内核实验5-API进0环 今天开始我们来分析系统api进0环的过程 系统调用3环部分的过程分析 先写一个应用程序然后我们调用一个readprocessmemory的系统api #include <Windows.h> #include <stdio.h>DWORD32 testVal 111;int main() {HANDLE h GetCurrentProc…

DatenLord前沿技术分享 No.36

达坦科技专注于打造新一代开源跨云存储平台DatenLord&#xff0c;通过软硬件深度融合的方式打通云云壁垒&#xff0c;致力于解决多云架构、多数据中心场景下异构存储、数据统一管理需求等问题&#xff0c;以满足不同行业客户对海量数据跨云、跨数据中心高性能访问的需求。在本周…

ChatGPT已进化到会看图和说话了,上教程

HI&#xff0c;同学们&#xff0c;我是赤辰&#xff0c;本期是第14篇AI工具类教程&#xff0c;文章底部准备了粉丝福利&#xff0c;看完后可领取&#xff01; ChatGPT又又又升级&#xff01;这次是支持语音聊天和图像问答。 这意味着用户现在除了键盘文本输入外&#xff0c;还可…

【JavaEE】多线程进阶(一)饿汉模式和懒汉模式

多线程进阶&#xff08;一&#xff09; 文章目录 多线程进阶&#xff08;一&#xff09;单例模式饿汉模式懒汉模式 本篇主要引入多线程进阶的单例模式&#xff0c;为后面的大冰山做铺垫 代码案例介绍 单例模式 非常经典的设计模式 啥是设计模式 设计模式好比象棋中的 “棋谱”…

三一充填泵:煤矿矸石无害化充填,煤炭绿色高效开采的破局利器

富煤贫油少气是我国的能源禀赋特征&#xff0c;决定了我国以煤炭为主的能源结构&#xff0c;煤炭为国民经济发展提供了重要的基础。煤炭开采过程会对土地、地下水、空气等环境造成较大的污染&#xff0c;但大宗固废煤矸石无害化充填的技术手段可以有效改善这样的情况&#xff0…

LabVIEW使用机器学习分类模型探索基于技能课程的学习

LabVIEW使用机器学习分类模型探索基于技能课程的学习 教育中的学习评估对教育工作者来说是一项繁琐的工作&#xff0c;但评估的好处是显着的。由于其开放性和复杂性&#xff0c;使用传统的评估方法为学生提供及时的支持一直具有挑战性。在Covid-19大流行期间突然转向在线学习&…

总结二:linux面经

文章目录 1、 Linux中查看进程运行状态的指令、查看内存使用情况的指令、tar解压文件的参数。2、文件权限怎么修改&#xff1f;3、说说常用的Linux命令&#xff1f;4、说说如何以root权限运行某个程序&#xff1f;5、 说说软链接和硬链接的区别&#xff1f;6、说说静态库和动态…

QT聊天室阶段性记录(完善中:注册功能,数据库存储)

server.h #ifndef SERVERDEMO_H #define SERVERDEMO_H#include <QObject> #include <QTcpServer> #include <QMap> #include <QSqlDatabase> //数据库管理类 #include <QSqlQuery> //执行sql语句的类 #include <QSqlRecord> //数据库…

最全MacBook选购指南 | 看完你就知道怎么买

最全MacBook选购指南 | 看完你就知道怎么买 作为MacBook的老用户大大小小的型号也都用了不少 那这么多台MacBook到底怎么选呢&#x1f4a1; . ☑️M1和Intel的MacBook有什么差别呢&#xff1f; 下半年苹果发布的两款MacBook都是苹果自研的芯片M1。在此之前苹果一直用的都是Inte…

解决报错:模块“react-redux“没有导出的成员“TypedUseSelectorHook”

在react整合typescript,redux时&#xff0c;写hook.ts时报这个错&#xff1a;模块"react-redux"没有导出的成员“TypedUseSelectorHook” 现象如下&#xff1a; 原因&#xff1a;react-redux版本太低&#xff0c;至少要升级到7.2.3以后才能包含TypedUseSelectorHook…

Clion中使用C/C++开发stm32程序

前言 从刚开始学习阶段&#xff0c;一直是用的keil5开发stm32程序&#xff0c;自从看到稚晖君推荐的CLion开发嵌入式程序后&#xff0c;这次尝试在CLion上开发stm32程序。 1、配置CLion用于STM32开发的环境 这里我就不详细写了&#xff0c;没必要重新写&#xff0c;网上教程很多…