网络编程day05(IO多路复用)
今日任务:
TCP多路复用的客户端、服务端:
服务端代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__ ", __LINE__);\perror(msg);\
}while(0)#define PORT 8888 //端口号的网络字节序,1024~49151
#define IP "192.168.125.2" //本机IP,ifconfigint keyboardEvents(void);
int cliconnectEvents(int sfd, struct sockaddr_in* pCin, fd_set *preadfds, int *pmaxfd);
int cliDealMsgEvnets(int newfd, struct sockaddr_in pCin[], fd_set *preadfds, int* pmaxfd);int main(int argc, const char *argv[])
{//创建流式套接字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 ipstruct sockaddr_in sin;sin.sin_family = AF_INET; //必须填AF_INET;sin.sin_port = htons(PORT); //端口号的网络字节序,1024~49151sin.sin_addr.s_addr = inet_addr(IP); //本机IP的网络字节序,ifconfig//绑定服务器的地址信息---》必须绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0){ ERR_MSG("bind");return -1; } printf("bind success\n");//将套接字转换成被动监听状态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; //存储集合中最大的文件描述符struct sockaddr_in saveCin[1024-3]; //将客户端的信息另存char buf[128] = ""; ssize_t res = 0;int newfd = -1; int s_res = 0;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__);//能运行到当前位置,则代表集合中有文件描述符准备就绪//判断哪个文件描述符准备就绪,走对应处理函数即可//当函数解除阻塞后,集合中会只剩下产生事件的文件描述符;例如://0号准备就绪,则集合中只剩下0号//sfd准备就绪,则集合中只能下sfd;//0和sfd均准备就绪,则0和sfd均存在//所以只需要遍历集合中剩下哪个文件描述符,就代表哪个文件描述符准备就绪for(int i=0; i<=maxfd; i++) {if(FD_ISSET(i, &tempfds) == 0) //若i所代表的文件描述符不存在,则遍历下一个文件描述符continue;//能运行到当前位置,说明i所代表的文件描述符在集合中。//判断i所代表的文件描述符是什么(0, sfd , 其他newfd),走对应处理函数即可if(0 == i) //说明0在集合中{printf("触发键盘输入事件\n");keyboardEvents();}else if(sfd == i) //说明sfd在集合中{printf("触发客户端连接事件\n");cliconnectEvents(sfd, saveCin, &readfds, &maxfd);}else {printf("触发客户端交互事件\n");cliDealMsgEvnets(i, saveCin, &readfds, &maxfd);}}} //关闭套接字close(sfd);return 0;
}int cliDealMsgEvnets(int newfd, struct sockaddr_in pCin[], fd_set *preadfds, int* pmaxfd)
{ssize_t res = -1; char buf[128] = ""; //接收数据res = recv(newfd, buf, sizeof(buf), 0); if(res < 0){ ERR_MSG("recv");return -1; } else if(0 == res){ printf("[%s:%d] newfd=%d 客户端下线__%d__\n", \inet_ntoa(pCin[newfd-3].sin_addr), ntohs(pCin[newfd-3].sin_port), newfd, __LINE__);close(newfd); //关闭文件描述符FD_CLR(newfd, preadfds); //剔除该文件描述符//更新maxfd, 从当前最大的文件描述符开始判断是否在集合中//若在,则该文件描述符就是最大文件描述符for(; *pmaxfd>=0; *pmaxfd--)if(FD_ISSET(*pmaxfd, preadfds))break;//while(!FD_ISSET(*pmaxfd, preadfds) && *pmaxfd-->=0);return 0;} printf("[%s:%d] newfd=%d : %s __%d__\n", \inet_ntoa(pCin[newfd-3].sin_addr), ntohs(pCin[newfd-3].sin_port), newfd, buf, __LINE__);//发送数据strcat(buf, "*_*"); if(send(newfd, buf, sizeof(buf), 0) < 0){ ERR_MSG("send");return -1; } printf("send success\n");return 0;
}int cliconnectEvents(int sfd, struct sockaddr_in* pCin, fd_set *preadfds, int *pmaxfd)
{struct sockaddr_in cin; //存储客户端的地址信息socklen_t addrlen = sizeof(cin);int newfd ;newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);if(newfd < 0){ ERR_MSG("accept");return -1; } printf("[%s:%d] newfd=%d 客户端连接成功__%d__\n", \inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, __LINE__);pCin[newfd-3] = cin; //将客户端信息另存FD_SET(newfd, preadfds); //将newfd添加到集合中*pmaxfd = *pmaxfd>newfd ? *pmaxfd:newfd; //更新maxfdreturn 0;
}int keyboardEvents(void)
{char buf[128] = ""; fgets(buf, sizeof(buf), stdin);buf[strlen(buf)-1] = 0;printf(":%s\n", buf);return 0;
}
客户端代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/select.h>
//自定义报错提示
#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__",__LINE__);\perror(msg);\
}while(0)
#define SER_PORT 8887
#define SER_IP "192.168.125.2"
/** function: TCP客户端* @param [ in] * @param [out] * @return */
int main(int argc, const char *argv[])
{//1.创建socket套接字,int cfd=socket(AF_INET,SOCK_STREAM,0);if(cfd<0){ERR_MSG("socket");return -1;}puts("socket create");//允许端口快速复用int reuse = 1;if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){ERR_MSG("setsockopt");return -1;}printf("允许端口快速复用成功\n");//2.连接服务端connectstruct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(SER_PORT);addr.sin_addr.s_addr=inet_addr(SER_IP);if(connect(cfd,(struct sockaddr*)&addr,sizeof(addr))<0){ERR_MSG("connect");return -1;}puts("connect success");//3.用多路复用实现实时的消息交流//3.1)创建集合,清空集合fd_set readfds,tem_readfds;FD_ZERO(&readfds);//3.2)添加需要使用的文件描述符FD_SET(0,&readfds);FD_SET(cfd,&readfds);//3.3)调用多路复用函数,阻塞char buf[128]="";while(1){tem_readfds=readfds;int sel_res=select(cfd+1,&tem_readfds,NULL,NULL,NULL);if(sel_res<0){ERR_MSG("select");return -1;}if(FD_ISSET(0,&tem_readfds)){//执行写操作;bzero(buf,sizeof(buf));printf("请输入>>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]='\0';if(strcmp(buf,"quit")==0)break;int send_res=send(cfd,buf,sizeof(buf),0);if(send_res<0){ERR_MSG("send");return -1;}puts("send success");}if(FD_ISSET(cfd,&tem_readfds)){//执行接受消息命令bzero(buf,sizeof(buf));int recv_res=recv(cfd,buf,sizeof(buf),0);if(recv_res<0){ERR_MSG("recv");return -1;}else if(recv_res==0){printf("socket peer has shutdown\n");break;}puts("recv success");printf("[%s:%d]:%s\n",SER_IP,SER_PORT,buf);}}//6.关闭close(cfd);return 0;
}
今日思维导图
相关文章:

网络编程day05(IO多路复用)
今日任务: TCP多路复用的客户端、服务端: 服务端代码: #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> …...

人声分离网站,帮你快速提取视频中的人声和背景音乐
今天给大家带来一个可以分离人声的网站——音分轨,他运用人工智能算法可以将音频中的人声部分和音乐部分分离,使我们的视频制作过程可以更方便。 我们点击右下角“选择文件”上传一个音频,上传好音频后,人工智能就开始处理我们上传…...

计算机网络常见问题
1.谈一谈对OSI七层模型和TCP/IP四层模型的理解? 1.1.为什么要分层? 在计算机中网络是个复杂的系统,不同的网络与网络之间由于协议,设备,软件等各种原因在协调和通讯时容易产生各种各样的问题。例如:各物流…...

上PICO,沉浸式观看亚运直播,参与跨国界游戏竞技
备受瞩目的杭州第19届亚运会,将于9月23日正式开幕。据悉,这也是有史以来项目最多的一届亚运会,除部分传统奥运项目外,还包含武术、藤球、板球、克柔术、柔术等亚洲特色项目,以及霹雳舞、电子竞技等深受年轻人喜爱的新兴…...
无重复字符的最长子串 - 力扣(LeetCode)
3. 无重复字符的最长子串 - 力扣(LeetCode) 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长…...
企业行政许可的种类有哪些?
从行政许可的性质、功能和适用条件的角度来说,大体可以划分为五类:普通许可、特许、认可、核准、登记。 1.普通许可 普通许可是一种允许符合特定条件的相对方行使某种权利的行为。在许多情况下,需要普通许可的活动都与国家安全、公共安全息…...

Flink--4、DateStream API(执行环境、源算子、基本转换算子)
星光下的赶路人star的个人主页 注意力的集中,意象的孤立绝缘,便是美感的态度的最大特点 文章目录 1、DataStream API1.1 执行环境(Execution Environment)1.1.1 创建执行环境 1.2 执行模式(Execution Mode)…...

#循循渐进学51单片机#指针基础与1602液晶的初步认识#not.11
1、把本节课的指针相关内容,反复学习3到5遍,彻底弄懂指针是怎么回事,即使是死记硬背也要记住,等到后边用的时候可以实现顿悟。学会指针,就是突破了C语言的一道壁垒。 2,1602所有的指令功能都应用一遍&#…...

Lua学习笔记:探究package
前言 本篇在讲什么 理解Lua的package 本篇需要什么 对Lua语法有简单认知 对C语法有简单认知 依赖Visual Studio工具 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 ★提高阅读体验★ 👉 ♠ 一级…...

【面试经典150 | 双指针】三数之和
文章目录 写在前面Tag题目来源题目解读解题思路方法一:暴力枚举方法二:双指针 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主,并附带一些对…...
现代卷积网络实战系列3:PyTorch从零构建AlexNet训练MNIST数据集
1、AlexNet AlexNet提出了一下5点改进: 使用了Dropout,防止过拟合使用Relu作为激活函数,极大提高了特征提取效果使用MaxPooling池化进行特征降维,极大提高了特征提取效果首次使用GPU进行训练使用了LRN局部响应归一化(…...

Django系列:Django应用(app)的创建与配置
Django系列 Django应用(app)的创建与配置 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article…...
Linux查看程序和动态库依赖的动态库
一. 前言 在一些时候,我们需要知道一个程序或者动态库所依赖的动态库有哪些。比如,当我们运行一个程序的时候,发现可能会报错,提示找不到某个符号,这时我们就需要知道程序依赖了什么库,从而添加对应需要的动…...
vue3 无法使用pnpm安装依赖 或 Cannot find module preinstall.js
创建.npmrc文件在根目录 shamefully-hoisttrue auto-install-peerstrue strict-peer-dependenciesfalse删除 node_modules 和 pnpm-lock.yaml 文件 重新 pnpm i 就可以啦...

C/C++连接数据库,包含完整代码。
C/C连接数据库 本篇文章意在简洁明了的在linux环境下使用C/C连接远程数据库,并对数据库进行增删查改等操作。我所使用的环境是centos7,不要环境除环境配置外,代码是大同小异的。完整代码在最底部!!! 1.前…...

AUTOSAR词典:CAN驱动Mailbox配置技术要点全解析
AUTOSAR词典:CAN驱动Mailbox配置技术要点全解析 前言 首先,请问大家几个小小问题,你清楚: AUTOSAR框架下的CAN驱动关键词定义吗?是不是有些总是傻傻分不清楚呢?CAN驱动Mailbox配置过程中有哪些关键配置参…...

C语言 coding style
头文件 The #define Guard #define的保护文件的唯一性,防止被多重包含 格式 : <PROJECT>_< FILE>_H_ PROJECT : XS FILE : MV_CTR 头文件的包含顺序 C System FilesOther LibrariesUser LibraryConditional include 作用域 局部变量 -变量定义时需要…...
Python办公自动化之PDF
Python操作PDF 1、Python操作PDF概述2、批量拆分3、批量合并4、提取内容(文字)5、提取内容(表格)6、提取图片7、PDF添加水印8、加密与解密1、Python操作PDF概述 Python操作PDF主要有两个库:PyPDF2和pdfplumber PyPDF2是一个用于处理PDF文件的Python第三方库 官网文档参考:…...
【每日一题Day331】LC2560打家劫舍 IV | 二分查找 + 贪心
打家劫舍 IV【LC2560】 沿街有一排连续的房屋。每间房屋内都藏有一定的现金。现在有一位小偷计划从这些房屋中窃取现金。 由于相邻的房屋装有相互连通的防盗系统,所以小偷 不会窃取相邻的房屋 。 小偷的 窃取能力 定义为他在窃取过程中能从单间房屋中窃取的 最大金额…...

JVM 参数详解
GC有两种类型:Scavenge GC 和Full GC 1、Scavenge GC 一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,堆的Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...