当前位置: 首页 > 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;封装与模块…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...