当前位置: 首页 > news >正文

《TCP/IP网络编程》(第十二章)I/O复用(2)

下面是基于I/O复用的回声服务器端和客户端代码

1.Linux系统

服务器端代码

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> // POSIX标准定义的通用函数,如close()
#include <arpa/inet.h> // 提供inet相关的函数,如inet_addr()
#include <sys/socket.h> // 提供socket相关的函数和数据结构
#include <signal.h>
#include <sys/wait.h>#define BUFF_SIZE 100 //缓冲区大小
void error_handling(char* message);int main(int argc, char *argv[]) 
{int serv_sock; // 服务器套接字int clnt_sock; // 客户端套接字struct sockaddr_in serv_addr; // 服务器地址结构struct sockaddr_in clnt_addr; // 客户端地址结构struct timeval timeout;//超时设置fd_set reads,cpy_reads;//读集合,拷贝读集合socklen_t clnt_addr_size; // 客户端地址结构的大小int fd_max,str_len,fd_num,i;//最大文件描述符,读集合大小,读集合大小,循环次数char opinfor[BUFF_SIZE];if(argc!=2){printf("Usage : %s <port>\n", argv[0]);exit(1); }// 创建一个服务器套接字serv_sock=socket(PF_INET, SOCK_STREAM, 0);//使用SOCK_STREAM创建TCP套接字if(serv_sock==-1) error_handling("socket() error"); // 初始化服务器地址结构memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family=AF_INET; // 地址族设置为IPv4serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); // 服务器地址设置为任意serv_addr.sin_port=htons(atoi(argv[1])); // 设置监听端口为命令行参数指定的端口// 绑定套接字,调用bind()函数分配ip地址和端口号if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)error_handling("bind() error"); // 监听套接字,最多监听5个连接if(listen(serv_sock, 5)==-1) error_handling("listen() error");//设置文件描述符FD_ZERO(&reads);FD_SET(serv_sock, &reads);fd_max=serv_sock;while(1){cpy_reads=reads;//把fd_set复制到cpy_reads//设置超时timeout.tv_sec=5;timeout.tv_usec=5000;if((fd_num=select(fd_max+1,&cpy_reads,0,0,&timeout))==-1){//调用select()函数,如果有文件描述符就绪,返回就绪的文件描述符个数,错误返回-1break;}if(fd_num==0){//超时返回0continue;}for(i=0; i<=fd_max+1; i++){//遍历所有文件描述符if(FD_ISSET(i, &cpy_reads)){//判断是否在cpy_reads中if(i==serv_sock){clnt_addr_size=sizeof(clnt_addr);clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);//接受连接请求FD_SET(clnt_sock, &reads);//将新连接的客户端套接字加入到reads中//更新最大文件描述符if(fd_max<clnt_sock){fd_max=clnt_sock;printf("Connected client: %d\n", clnt_sock);}}else{str_len=read(i, opinfor, BUFF_SIZE);//读取客户端发送的数据if(str_len==0){//如果客户端关闭连接FD_CLR(i, &reads);//从reads中删除该文件描述符close(i);printf("closed client: %d\n", i);}else{write(i, opinfor, str_len);//发送数据给客户端}}}}}// 关闭服务器套接字close(serv_sock);return 0; 
}void error_handling(char *message)
{fputs(message, stderr); fputc('\n', stderr); exit(1); 
}

客户端代码
这里使用的是(第四章)基于TCP的服务器端/客户端(1)中的回声服务器客户端代码

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <arpa/inet.h> 
#include <sys/socket.h> #define BUF_SIZE 1024
void error_handling(char *message); int main(int argc, char *argv[]) 
{int sock; // 客户端套接字struct sockaddr_in serv_addr; // 服务器地址结构char message[BUF_SIZE]; // 用于存储从服务器接收的消息int str_len,i; // 读取的字节数if (argc != 3){printf("Usage : %s <IP> <port>\n", argv[0]);exit(1); }// 创建一个客户端套接字sock = socket(PF_INET, SOCK_STREAM, 0);if (sock == -1) error_handling("socket() error"); // 初始化服务器地址结构memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET; // 地址族设置为IPv4serv_addr.sin_addr.s_addr = inet_addr(argv[1]); // 设置服务器IP地址serv_addr.sin_port = htons(atoi(argv[2])); // 设置服务器端口号// 发送连接请求if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)error_handling("connect() error"); else{printf("Connected.....\n");}while(1){printf("Input message(Q to quit): ");fgets(message, BUF_SIZE, stdin);if (!strcmp(message, "Q\n") || !strcmp(message, "q\n")){break;}write(sock, message, strlen(message));str_len = read(sock, message, sizeof(message) - 1);message[str_len] = 0;printf("Message from server: %s \n", message);}// 关闭套接字close(sock);return 0; 
}void error_handling(char* message){fputs(message, stderr); fputc('\n', stderr); exit(1); 
}

运行结果
在这里插入图片描述
回声服务器/客户端可以正常运行,也可以单独关闭某一个客户端的连接

2.Windows系统

Windows系统下的select函数和Linux系统下的完全相同,详情查看(第十二章)I/O复用(1)

服务器端代码

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")// 指定链接到winsock库#define BUFF_SIZE 30 //缓冲区大小
void error_handling(char* message);int main(int argc, const char* argv[])
{WSADATA wsaData;// Windows Sockets API需要的数据结构SOCKET hServSock, hClntSock;SOCKADDR_IN servAddr, clntAddr;TIMEVAL timeout;fd_set reads,cpy_reads;char message[BUFF_SIZE];int strlen,clntAdrSize,fdNum,i;if (argc != 2) {printf("Usage : %s <port>\n", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)// 初始化Windows Sockets服务error_handling("WSAStartup() error!");//创建套接字	hServSock = socket(PF_INET, SOCK_STREAM, 0);//使用SOCK_STREAM,即创建tcp套接字if (hServSock == INVALID_SOCKET)error_handling("socket() error");memset(&servAddr, 0, sizeof(servAddr));servAddr.sin_family = AF_INET;servAddr.sin_addr.s_addr = htonl(INADDR_ANY); servAddr.sin_port = htons(atoi(argv[1]));// 将socket绑定到地址和端口if (bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)error_handling("bind() error");if (listen(hServSock, 5) == SOCKET_ERROR)error_handling("listen() error");//设置文件描述符集合FD_ZERO(&reads);FD_SET(hServSock, &reads);while (1) {cpy_reads = reads;//将reads复制到cpy_readstimeout.tv_sec = 5;//设置超时时间timeout.tv_usec = 5000;//等待文件描述符集合中的描述符就绪fdNum = select(0, &cpy_reads, NULL, NULL, &timeout);if (fdNum == SOCKET_ERROR){//有错误退出break;}if(fdNum == 0){//超时continue;}for (i = 0; i < fdNum; i++){//遍历所有文件描述符if (FD_ISSET(cpy_reads.fd_array[i], &reads)){//判断是否在cpy_reads中if (cpy_reads.fd_array[i] == hServSock){//有新的客户端连接clntAdrSize = sizeof(clntAddr);hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &clntAdrSize);//接受客户端连接if (hClntSock == INVALID_SOCKET){error_handling("accept() error");}else{printf("connected client: %d \n",hClntSock);FD_SET(hClntSock, &reads);//将新的客户端socket添加到文件描述符集合中}	}else{//有客户端发送数据strlen = recv(cpy_reads.fd_array[i], message, BUFF_SIZE, 0);//接收数据if (strlen == 0){//如果客户端关闭连接FD_CLR(cpy_reads.fd_array[i], &reads);//从文件描述符集合中删除closesocket(cpy_reads.fd_array[i]);printf("closed client: %d\n",cpy_reads.fd_array[i]);}else{//发送数据send(cpy_reads.fd_array[i],message, strlen, 0);printf("message from client %d : %s", hClntSock,message);}}}}}closesocket(hServSock);// 关闭服务器socketWSACleanup();// 清理Windows Sockets服务return 0;
}void error_handling(char* message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

客户端代码
这里使用的是(第四章)基于TCP的服务器端/客户端(1)中的回声服务器客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")// 指定链接到winsock库#define BUF_SIZE 1024
void ErrorHandling(const char *message);int main(int argc, char *argv[])
{WSADATA wsaData;SOCKET hSocket;SOCKADDR_IN servAddr;// 用于存储服务器的地址信息char message[BUF_SIZE];// 用于接收从服务器发送的消息int strLen;// 接收的消息长度if (argc != 3) {printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}// 初始化Windows Sockets服务if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHandling("WSAStartup() error!");//创建套接字hSocket = socket(PF_INET, SOCK_STREAM, 0);if (hSocket == INVALID_SOCKET)ErrorHandling("socket() error");memset(&servAddr, 0, sizeof(servAddr));servAddr.sin_family = AF_INET;// 设置地址族为IPv4servAddr.sin_addr.s_addr = inet_addr(argv[1]);// 设置服务器的IP地址servAddr.sin_port = htons(atoi(argv[2]));// 设置服务器的端口号// 尝试连接到服务器if (connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)ErrorHandling("connect() error!");else{printf("Connected......\n");}while(1){fputs("Input message(Q to quit): ",stdout);fgets(message, BUF_SIZE, stdin);if(!strcmp(message, "Q\n") || !strcmp(message, "q\n")){break;}send(hSocket, message, strlen(message), 0);strLen= recv(hSocket, message, sizeof(message)-1, 0);message[strLen]= 0;printf("Message from server: %s \n", message);}closesocket(hSocket);// 关闭套接字WSACleanup();// 清理Windows Sockets服务return 0;
}void ErrorHandling(const char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

运行结果
在这里插入图片描述

相关文章:

《TCP/IP网络编程》(第十二章)I/O复用(2)

下面是基于I/O复用的回声服务器端和客户端代码 1.Linux系统 服务器端代码 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> // POSIX标准定义的通用函数&#xff0c;如close() #include <arpa/inet.h> //…...

AI企业需要“联盟营销”?一文带你探索AI企业营销新玩法!

为什么联盟营销对AI业务有较大优势 联盟营销在电商领域、saas领域与其他产品领域同样有效。在AI业务中&#xff0c;它有效的原因与其他领域大不相同。 高好奇心和试用率 AI领域是创新的热点。它吸引了一群渴望探索和尝试每一项新技术的人群。这种蓬勃的好奇心为聪明的AI企业提…...

你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

目录 一、onMounted的前世今生 1.1、onMounted是什么 1.2、onMounted在vue2中的前身 1.2.1、vue2中的onMounted 1.2.2、Vue2与Vue3的onMounted对比 1.3、vue3中onMounted的用法 1.3.1、基础用法 1.3.2、顺序执行异步操作 1.3.3、并行执行多个异步操作 1.3.4、执行一次…...

JavaWeb基础(一)-IO操作

Java I/O工作机制&#xff1a; 注&#xff1a;简要笔记&#xff0c;示例代码可能较少&#xff0c;甚至没有。 1、Java 的 I/O 类库的基本架构。 ​ Java 的 I/O 操作类在包 java.io 下&#xff0c;大概有将近80个类&#xff0c;这些类大概可以分为如下四组。 基于字节操作的…...

拼多多(PDD)社招一面原题

未成年游戏退费 5 月 28 日&#xff0c;中国互联网协会发布《未成年人网络游戏服务消费管理要求&#xff08;征求意见稿&#xff09;》团体标准。 该标准是游戏行业首个完整的消费管理规范&#xff0c;可用于未成年人游戏消费退费纠纷解决&#xff0c;也可为相关行政部门、司法…...

类中使用QtConcurrent::run

在QtConcurrent::run中调用类的成员函数时&#xff0c;你需要注意几个关键点&#xff1a; 对象生命周期&#xff1a;你需要确保在QtConcurrent::run调用的整个期间&#xff0c;类对象都是有效的。如果对象在成员函数执行期间被销毁&#xff0c;将会导致未定义行为。成员函数访…...

基于深度学习的中文情感分析系统python flask

基于python的毕业设计 基于深度学习的中文情感分析系统(flask)(源码说明文档演示) 毕业设计课程设计期末大作业、课程设计、高分必看&#xff0c;下载下来&#xff0c;简单部署&#xff0c;就可以使用。 包含&#xff1a;项目源码、数据库脚本、软件工具等&#xff0c;该项目…...

Mysql联合索引

对mysql联合索引的认识 文章目录 对mysql联合索引的认识最左原则匹配一、最左匹配的原理&#xff1f;二、实战 最左原则匹配 所谓最左原则指的就是如果你的 SQL 语句中用到了联合索引中的最左边的索引&#xff0c;那么这条 SQL 语句就可以利用这个联合索引去进行匹配&#xff…...

Linux基础指令用户管理003

继Linux基础指令002我们讲了如何设置用户密码以及修改用户信息&#xff0c;我们讲一下高级用户管理。 操作系统 CentOS Stream 9 高级用户管理 visudo 用于普通用户临时提升权限执行命令&#xff0c;如下图 [yylocalhost ~]$ cp -av /etc/passwd{,_bak} /etc/passwd ->…...

java图书电子商务网站的设计与实现源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的图书电子商务网站的设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 图书电子商…...

全球首个多语种手语视频生成模型诞生:SignLLM

近日&#xff0c;一项名为 SignLLM 的新型 AI 技术取得了突破性进展&#xff0c;或将彻底改变听障人士的沟通方式。作为全球首个多语种手语生成模型&#xff0c;SignLLM 能够将输入的文本或语音指令&#xff0c;实时转化为对应的手语手势视频&#xff0c;为打破语言障碍、促进信…...

初学C语言100题:经典例题节选(源码分享)

1.输出10000以内所有完数 完数的概念 一个正整数的所有因子&#xff08;除了自身以外的约数&#xff09;的和恰巧等于它本身 #include <stdio.h>int main() {int i 0;for (i 2; i < 10000; i)//生成1到10000之间的数{int j 0;int sum 0;//注意这里的sum每次循环结…...

C++设计模式之策略模式、迭代器模式、适配器模式、工厂模式、超级工厂模式、享元模式、代理模式

文章目录 一、介绍1.毫无价值的使用虚函数例子 二、策略模式1.策略模式2.多重策略与迭代器模式3.不要什么东西都塞一块 三、适配器模式1.跨接口的适配器2.跨接口的适配器 四、工厂模式1.工厂模式2.超级工厂模式3.RAII 自动管理内存4.工厂模式实战 五、享元模式1.享元模式2.代理…...

18 js时间对象

时间对象是一种复杂数据类型&#xff0c;用来存储时间 创建时间对象 内置构造函数创建 语法&#xff1a;var 时间名new Date() var datenew Date()console.log(date) //Wed May 29 2024 16:03:47 GMT0800 (中国标准时间) 创建指定日期 当参数为数字——>在格林威治的时间基…...

安卓赤拳配音v1.0.2Ai配音神器+百位主播音色

Ai配音神器 本人自用版本&#xff01;超级稳定&#xff01;百位主播音色 登陆即可用 链接&#xff1a;https://pan.baidu.com/s/1WVsrYZqLaPAriHMMLMdPBg?pwdz9ru 提取码&#xff1a;z9ru...

前端面试题日常练-day40 【面试题】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末 1. Bootstrap 的栅格系统是基于&#xff08; &#xff09;进行布局的。A. 像素 B. 百分比 C. 媒体查询 2. 在 Bootstrap 中&#xff0c;要创建一个按钮&#xff0c;可以使用&#xff08; &#xff…...

UG NX二次开发(C#)-UFun函数-利用UFPart.Export导出模型中的对象并创建一个新的part

文章目录 1、前言2、UF_PART_export函数定义3、UF_PART_export_with_options函数定义4、代码1、前言 在UG NX 10.0二次开发中,需要用到将装配体中通过几何建模创建的对象独立创建一个part文件,所以查找了下UFun函数,即是UF_PART_export 和UF_PART_export_with_options两个函…...

SFOS2:组件介绍

一、前言 在sailfish os application的开发过程中&#xff0c;几乎是困难重重&#xff0c;因为我暂未找到具有完整性、指导性、易懂性的开发文档&#xff0c;特别是组件的使用&#xff0c;现决定将自己的探究结果记录下来。因此&#xff0c;这篇文章只会具有参考价值&#xff0…...

交换机的三层交换技术

现有pc1与pc2不在同一个网段之下&#xff0c;通过交换机相连接。 进人交换机1&#xff0c;创建两个vlan 10和vlan 20 &#xff0c;进入串口2设置串口模式为access&#xff0c;并且设置默认vlan为10.进入串口3设置串口模式为access&#xff0c;并且设置默认vlan为20. 进入串口1…...

探秘URL的奥义:JavaScript中轻松获取页面参数值的N种姿势【含代码示例】

探秘URL的奥义&#xff1a;JavaScript中轻松获取页面参数值的N种姿势【含代码示例】 URL基础知识补给站基础案例&#xff1a;直接解析URL案例一&#xff1a;使用URLSearchParams案例二&#xff1a;传统字符串分割法 高级策略&#xff1a;动态与安全案例三&#xff1a;封装与模块…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...