网络编程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.xdnf.cn/news/139634.html

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

相关文章

【动态规划刷题 17】回文子串 最长回文子串

647. 回文子串 链接: 647. 回文子串 给你一个字符串 s &#xff0c;请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串&#xff0c;即使是由…

2023华为杯研究生数学建模F题思路分析

更多思路代码查看文末名片 1.如何有效应用双偏振变量改进强对流预报&#xff0c;仍是目前气象预报的重点难点问题。请利用题目提供的数据&#xff0c;建立可提取用于强对流临近预报双偏振雷达资料中微物理特征信息的数学模型。临近预报的输入为前面一小时&#xff08;10帧&…

不再跳票Fedora 26 正式发布!

经过延期和跳票&#xff0c;Fedora 26终于和大家见面了&#xff0c;下面是Fedora 项目负责人Matthew Miller感谢信 大家好&#xff0c;我很高兴地宣布&#xff0c;从即刻起 Fedora 26 正式可用了。你可以从下面了解到具体信息&#xff0c;也可以马上开始下载&#xff1a; •下载…

CentOS在应用程序菜单中创建快捷方式

背景&#xff1a; 在CentOS系统中&#xff0c;安装一些应用软件的时候&#xff0c;我们可能会自定义安装路径&#xff1b;这样在安装完应用程序后&#xff0c;在“Application”下&#xff0c;可能找不到对应的快捷键&#xff1b;这是就需要手动去创建跨界方式。 应用&#xf…

stm32之GPIO库函数点灯分析

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

MySQL备份及恢复

目录 MySQL备份 MySQL备份方法 备份策略 mysql的完全备份 mysql的增量备份 MySQL恢复 mysql完全恢复 mysql增量备份的恢复 MySQL备份 MySQL备份是基于对MySQL的日志进行备份&#xff0c;且恢复也是通过日志进行数据恢复。 MySQL备份方法 物理备份&#xff1a;直接对…

北京智和信通亮相2023IT运维大会,共话数智浪潮下自动化运维新生态

2023年9月21日&#xff0c;由IT运维网、《网络安全和信息化》杂志社联合主办的“2023&#xff08;第十四届&#xff09;IT运维大会”在北京成功举办。大会以“以数为基 智引未来”为主题&#xff0c;北京智和信通技术有限公司&#xff08;下文简称&#xff1a;北京智和信通&…

爱看小说手机网源码全站带数据带自动采集程序/ThinkPHP内核小说网站源码+书库数据库带自动采集

爱看小说手机网源码全站带数据带自动采集程序&#xff0c;爱看小说程序源码2W条数据全站打包,自动采集程序网站源码,后台已经更新5个采集规则可以采集小说30万本大概约10G。 分享的这一款自带2w数据爱看小说网源码全站带数据打包,ThinkPHP内核小说网站源码带听书等全部插件&am…

TouchGFX之画布控件

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

矩阵论—凯莱-哈密顿定理

凯莱-哈密顿定理内容 凯莱-哈密顿定理典型例题 典型例题 我们先来观察这个题目&#xff0c;题目要求&#xff0c;若直接将矩阵A 代入计算&#xff0c;则会非常复杂&#xff0c;因此&#xff0c;这条路是走不通的。 我们试着引入我们今天介绍的凯莱-哈密顿定理来解这个…

Linux,计算机网络,数据库

Linux&#xff0c;计算机网络&#xff0c;数据库&#xff0c;操作系统 一、Linux1、linux查看进程2、linux基本命令3、top命令、查看磁盘 二、计算机网络1、HTTP的报文段请求 Repuest响应 Response 2、HTTP用的什么连接3、TCP的三次握手与四次挥手三次握手四次挥手 4、在浏览器…

【MATLAB第76期】基于MATLAB的代表性样本筛选方法合集(针对多输入单输出数据)

【MATLAB第76期】基于MATLAB的代表性样本筛选方法合集&#xff08;针对多输入单输出数据&#xff09; 前有筛选变量方法&#xff0c;如局部敏感性分析和全局敏感性分析方法介绍 。 今天提出另外一种思路&#xff0c;去对样本进行筛选。 使用场景&#xff1a; 场景1&#xff1a…

Python 实现 PDF 文件转换为图片 / PaddleOCR

文章用于学习记录 文章目录 前言一、PDF 文件转换为图片二、OCR 图片文字识别提取三、服务器端下载运行 PaddleOCR四、下载权重文件总结 前言 文字识别&#xff08;Optical Character Recognition&#xff0c;简称OCR&#xff09;是指将图片、扫描件或PDF、OFD文档中的打印字符…

Mybatis工作流程及原理详解

一、概述 1.何为mybatis&#xff1f; MyBatis 是一款优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将接口和 J…

数据仓库数据库

在当今的数字化时代&#xff0c;数据存储和管理是非常重要的领域。数据仓库和数据库是两个重要的数据存储和管理工具&#xff0c;它们有着不同的特点和用途。 一、数据仓库与数据库的定义 1. 数据仓库 数据仓库&#xff0c;是为企业所有级别的决策制定过程&#xff0c;提供所…

报错处理:Error: Redis server is running but Redis CLI cannot connect

嗨&#xff0c;读者朋友们&#xff01;今天我来跟大家分享一个我在运维过程中遇到的一个关于Linux上运行Redis服务时的报错及解决方法。 报错信息如下&#xff1a; Error: Redis server is running but Redis CLI cannot connect 这个报错信息表明Redis服务器已经运行&#xff…

达梦数据库-DW-国产化--九五小庞

武汉达梦数据库股份有限公司成立于2000年&#xff0c;是国内领先的数据库产品开发服务商&#xff0c;国内数据库基础软件产业发展的关键推动者。公司为客户提供各类数据库软件及集群软件、云计算与大数据等一系列数据库产品及相关技术服务&#xff0c;致力于成为国际顶尖的全栈…

【笔记】ubuntu 20.04 + mongodb 4.4.14定时增量备份脚本

环境 ubuntu 20.04mongodb 4.4.14还没实际使用&#xff08;20230922&#xff09;后续到10月底如果有问题会修改 原理 只会在有新增数据时生成新的备份日期目录备份恢复时&#xff0c;如果恢复的数据库未删除&#xff0c;则会覆盖数据 准备 准备一个文件夹&#xff0c;用于…

thinkphp8路由

thinkphp8已出来有好一段时间了。这些天闲来无事&#xff0c;研究了下tp8的路由。默认情况下&#xff0c;tp8的路由是在route\app.php的文件里。但在实际工作中&#xff0c;我们并不会这样子去写路由。因为这样不好管理。更多的&#xff0c;是通过应用级别去管理路由。假如项目…

网络初识

一 IP 地址 概念: IP 地址主要用于表示网络主机、其他网络设备&#xff08;如路由器&#xff09;的网络地址。简单说&#xff0c;IP地址用于定位主机的网络地址 格式 IP 地址是一个32为的二进制数&#xff0c;通常被分割为4个“8位二进制数“&#xff08;也就是4个字节&…