网络编程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;
}

今日思维导图

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

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

相关文章

uniapp 内容展开组件

uni-collapse折叠面板并不符合需求&#xff0c;需要自己写一个。 效果展示&#xff1a; 代码&#xff1a; &#xff08;vue3版本&#xff09; <template><view class"collapse-view"><view class"collapse-content"><swiper:autopl…

OpenHarmony应用核心技术理念与需求机遇简析

一、核心技术理念 图片来源&#xff1a;OpenHarmony官方网站 二、需求机遇简析 新的万物互联智能世界代表着新规则、新赛道、新切入点、新财富机会;各WEB网站、客户端( 苹果APP、安卓APK)、微信小程序等上的组织、企业、商户等;OpenHarmony既是一次机遇、同时又是一次大的挑战&…

好用的记笔记app选哪个?

当你在日常生活中突然获得了一个灵感&#xff0c;或者需要记录会议的重要内容&#xff0c;或者是学校课堂上的笔记&#xff0c;你通常会拿出手机&#xff0c;因为它总是在你身边&#xff0c;随时可用。这时候&#xff0c;一款好的记笔记App可以让你事半功倍。 敬业签是一款全面…

「UG/NX」Block UI 从列表选择部件SelectPartFromList

✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#

Qt5开发及实例V2.0-第十五章-Qt单元测试框架

Qt5开发及实例V2.0-第十五章-Qt单元测试框架 第15章 Qt 5单元测试框架15.1 QTestLib框架15.2 简单的Qt单元测试15.3 数据驱动测试15.4 简单性能测试 本章相关例程源码下载1.Qt5开发及实例_CH1501.rar 下载2.Qt5开发及实例_CH1502.rar 下载3.Qt5开发及实例_CH1503.rar 下载4.Qt5…

构建个人云存储:本地电脑搭建SFTP服务器,开启公网访问,轻松共享与管理个人文件!

本地电脑搭建SFTP服务器&#xff0c;并实现公网访问 文章目录 本地电脑搭建SFTP服务器&#xff0c;并实现公网访问1. 搭建SFTP服务器1.1 下载 freesshd 服务器软件1.3 启动SFTP服务1.4 添加用户1.5 保存所有配置 2. 安装SFTP客户端FileZilla测试2.1 配置一个本地SFTP站点2.2 内…

stm32之GPIO库函数点灯分析

stm32官方为了方便开发者&#xff0c;利用CubeMX 生成HAL库有关的C代码。HAL库就是硬件抽象层(hardware abstraction layer)&#xff0c;生成一系列的函数帮助我们快速生成工程&#xff0c;脱离复杂的寄存器配置。stm32相对于51来功能强大&#xff0c;但是寄存器的数量也不是一…

C++核心编程——P22-练习案例2:点和圆的关系

在一个类中可以让另一个类作为这个类的成员 #include<iostream> using namespace std; class Point//点类 { public:void setx(int x){c_x x;}int getx(){return c_x;}void sety(int y){c_y y;}int gety(){return c_y;}//建议将属性设置为私有&#xff0c;对外提供接口…

pcl--第十二节 2D和3D融合和手眼标定

2D&3D融合 概述 截止目前为止&#xff0c;我们学习了机器人学&#xff0c;学习了2D和3D视觉算法。我们也学习了2D相机(图像数据的来源)和3D相机(点云数据的来源)工作原理。 实际上&#xff0c;我们最终要做的&#xff0c;是一个手眼机器人系统。在这个系统里&#xff0c…

pytorch学习------常见的优化算法

优化算法 优化算法就是一种调整模型参数更新的策略&#xff0c;在深度学习和机器学习中&#xff0c;我们常常通过修改参数使得损失函数最小化或最大化。 优化算法介绍 1、梯度下降算法&#xff08;batch gradient descent BGD&#xff09; 每次迭代都需要把所有样本都送入&…

深入了解队列数据结构:定义、特性和实际应用

文章目录 &#x1f34b;引言&#x1f34b;队列的定义&#x1f34b;队列的实现&#x1f34b;队列的应用&#x1f34b;练习题&#x1f34b;结语 &#x1f34b;引言 队列&#xff08;Queue&#xff09;是计算机科学中一种重要的数据结构&#xff0c;它常用于各种应用程序中&#x…

Hive【Hive(一)DDL】

前置准备 需要启动 Hadoop 集群&#xff0c;因为我们 Hive 是在 Hadoop 集群之上运行的。 从DataGrip 或者其他外部终端连接 Hive 需要先打开 Hive 的 metastore 进程和 hiveserver2 进程。metastore 和 hiveserver2 进程的启动过程比较慢&#xff0c;不要着急。 Hive DDL 数据…

基于SpringBoot的网上超市系统的设计与实现

目录 前言 一、技术栈 二、系统功能介绍 管理员功能实现 用户功能实现 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计…

微软在Windows 11推出Copilot,将DALL-E 3集成在Bing!

美东时间9月21日&#xff0c;微软在美国纽约曼哈顿举办产品发布会&#xff0c;生成式AI成为重要主题之一。 微软表示&#xff0c;Copilot将于9月26日在Windows 11中推出&#xff1b;Microsoft 365 Copilot 将于11 月1日向企业客户全面推出&#xff1b;将OpenAI最新的文本生成图…

【论文阅读 08】Adaptive Anomaly Detection within Near-regular Milling Textures

2013年&#xff0c;太老了&#xff0c;先不看 比较老的一篇论文&#xff0c;近规则铣削纹理中的自适应异常检测 1 Abstract 在钢质量控制中的应用&#xff0c;我们提出了图像处理算法&#xff0c;用于无监督地检测隐藏在全局铣削模式内的异常。因此&#xff0c;我们考虑了基于…

GitHub Copilot Chat

9月21日&#xff0c;GitHub在官网宣布&#xff0c;所有个人开发者可以使用GitHub Copilot Chat。用户通过文本问答方式就能生成、检查、分析各种代码。 据悉&#xff0c;GitHub Copilot Chat是基于OpenAI的GPT-4模型打造而成&#xff0c;整体使用方法与ChatGPT类似。例如&…

TouchGFX之画布控件

TouchGFX的画布控件&#xff0c;在使用相对较小的存储空间的同时保持高性能&#xff0c;可提供平滑、抗锯齿效果良好的几何图形绘制。 TouchGFX 设计器中可用的画布控件&#xff1a; LineCircleShapeLine Progress圆形进度条 存储空间分配和使用​ 为了生成反锯齿效果良好的…

华为云云耀云服务器L实例评测 | minikube部署和使用

### 1 安装Docker 按照官网[Docker docs](https://docs.docker.com/engine/install/centos/)指引安装&#xff1a; shell yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install docker-ce docker-…

[C++随笔录] vector模拟实现

vector模拟实现 基本结构天选之子构造拷贝构造析构operator 空间reserveresizesize && capacity 增insertpush_back 删erasepop_back 查 && 改swapoperator[] 源码 基本结构 // 可以是不同类型, 用类模板 template <class T> class vector { public:// 源…