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

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

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); 
}

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

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);
}

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

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

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

相关文章

零售抄表系统是什么?

1.零售抄表系统的简述 零售抄表系统是一种现代化自动化软件&#xff0c;用以监控和管理方法各种各样公共事业的消耗&#xff0c;如电力工程、水、天然气等。这类系统规避了传统的人工抄水表方法&#xff0c;提升了效率&#xff0c;降低了不正确&#xff0c;并且提供即时用户数…

Blazor入门-连接MySQL的简单例子:列出数据+简单查询

参考&#xff1a; ASP.NET Core 6.0 Blazor Server APP并使用MySQL数据库_blazor mysql-CSDN博客 https://blog.csdn.net/mzl87/article/details/129199352 本地环境&#xff1a;win10, visual studio 2022 community, mysql 8.0.33 (MySQL Community Server), net core 6.0 目…

c++ stack容器

在C中&#xff0c;std::stack 是一个标准模板库&#xff08;STL&#xff09;中的容器适配器&#xff0c;它提供了一种后进先出&#xff08;LIFO, Last In First Out&#xff09;的数据结构。std::stack 容器适配器基于底层容器&#xff08;默认是 std::deque&#xff0c;但也可…

方法的重写--5.29

当子类对父类的方法不满意时&#xff0c;可以进行重写&#xff0c;但是方法名字要与父类一样。 举例&#xff0c;我用people来举例&#xff0c;我是打工人&#xff0c;然后再创一个student类&#xff0c;重写方法我不是打工人&#xff0c;我是读书人。代码如下&#xff0c;发现…

宠物空气净化器:猫毛过敏者的终极解决方案,养猫不再是梦!

我有一位朋友&#xff0c;猫猫的深度爱好者。但是每当与猫咪接触的时候就会出现过敏反应&#xff0c;例如浑身发痒、打喷嚏、呼吸困难、起红疹等。对此&#xff0c;有专家给出权威的解释&#xff1a;引发铲屎官过敏的“罪魁祸首”是一种叫做Feld1的蛋白质成分&#xff0c;而这种…

电表自动抄表系统:智能时代的能源管理新方式

1.界定和功能 电表自动抄表系统是一种现代化电力计量技术&#xff0c;它利用先进的通讯技术和互联网&#xff0c;完成了远程控制、实时电磁能数据采集和处理。系统的主要作用包含全自动载入电表数据信息、实时检测电力应用情况、出现异常报案及其形成详尽能源使用报告&#xf…

【Vue】v-for列表渲染指令

Vue 提供了 v-for 列表渲染指令&#xff0c;用来辅助开发者 基于数据循环&#xff0c; 多次渲染整个元素。 --> 数据指的是&#xff1a;数组、对象、数字… v-for 指令需要使用 (item, index) in arr 形式的特殊语法&#xff0c;其中&#xff1a; item 是数组中的每一项in…

dbserver 软件 展示 全部模式库

目录 1 问题2 实现 1 问题 dbserver 软件 展示 全部模式库 2 实现 以上就可以了

React Native 之 接口请求(十八)

React Native 提供了和 web 标准一致的Fetch API&#xff0c;用于满足开发者访问网络的需求。如果你之前使用过XMLHttpRequest(即俗称的 ajax)或是其他的网络 API&#xff0c;那么 Fetch 用起来将会相当容易上手。 发起请求API&#xff08;fetch&#xff09; fetch(https://my…

【busybox记录】【shell指令】mkfifo

目录 内容来源&#xff1a; 【GUN】【mkfifo】指令介绍 【busybox】【mkfifo】指令介绍 【linux】【mkfifo】指令介绍 使用示例&#xff1a; 创建管道文件 - 创建的时候同时指定文件权限 常用组合指令&#xff1a; 指令不常用/组合用法还需继续挖掘&#xff1a; 内容来…

前端应用开发实验:表单控件绑定

目录 实验目的相关知识点实验内容代码实现效果 实验目的 &#xff08;1&#xff09;熟练掌握应用v-model指令实现双向数据绑定的方法&#xff0c;学会使用 v-model指令绑定文本框、复选框、单选按钮、下拉菜单&#xff1b; &#xff08;2&#xff09;学会值绑定&#xff08;将…

display: none 和 visibility: hidden 的共性与区别

display: none 和 visibility: hidden 的共性与区别 共性&#xff1a;display: none 和 visibility: hidden 都是用于设置元素可见性的样式 区别 display: none 使元素及其占位完全消失&#xff1a;元素及其所有子元素将从文档流和布局中完全消失&#xff0c;就像它们不存在一…

C++ 封装线程池(结合QT支持信号机制)

纯C风格线程池 纯C 风格线程池可参考这篇文章 https://llfc.club/category?catid225RaiVNI8pFDD5L4m807g7ZwmF#!aid/2c2IJUcCUOfzEQQRRdOXYIZuCjP 视频教程 相关线程池和并发编程的视频可以看看这个连接&#xff1a; https://www.bilibili.com/video/BV1Xt421H7M7/?vd_s…

【C language】判断一个正整数是否是2^n

题解&#xff1a;判断一个正整数是否是2^n(位运算方法) 1.题目 判断一个正整数是否是2^n 2.位运算法 思路&#xff1a;干掉二进制最右边的1&#xff0c;看是否是0 int main() {int num 16;if ((num & (num - 1)) 0) printf("the num is a 2^n");else print…

Ubuntu 修改镜像源为阿里云【详细步骤】

文章目录 修改步骤第 1 步:安装 vim 软件第 2 步:备份源第 3 步:修改为阿里云镜像附录 - 其它版本配置ubuntu 14.04 LTS (trusty) (EOL)ubuntu 16.04 LTS (xenial) (EOL)ubuntu 18.04 LTS (bionic)ubuntu 20.04 LTS (focal)ubuntu 22.04 LTS (jammy)ubuntu 23.04 (lunar)ubu…

基于51单片机的交通灯设计

一.硬件方案 本设计能模拟基本的交通控制系统&#xff0c;用红绿黄灯表示禁行&#xff0c;通行和等待的信号发生&#xff0c;还能进行倒计时显示。按键可以控制禁行、深夜模式、复位、东西通行、南北通行、时间加、时间减、切换等功能。共四个二位阴极数码管&#xff0c;东南西…

polarctf靶场[reverse]shell、PE结构、拼接

[reverse]shell 考点&#xff1a;脱壳 将所解压的文件拖入DIE有无有壳&#xff0c;文件类型 发现有UPX壳&#xff0c;是32位的文件&#xff0c;先脱壳 用FFI工具脱壳 将脱壳后的程序用32位IDA进行反汇编 点开_main_0函数进行查看 看到flag&#xff0c;&#xff08;F5&#…

小红书广告如何推广?投放费用是多少?

小红书以其独特的社区文化和用户粘性&#xff0c;成为了众多品牌争相推广的热门平台&#xff0c;如何在小红书上有效推广广告&#xff0c;让品牌信息精准触达目标用户&#xff0c;成为了众多营销人员关注的焦点&#xff0c;云衔科技为企业提供专业的开户和代运营服务。 一、小…

TOGAF企业架构章节(核心)知识点(一)

TOGAF标准9.2一共有 6 部分&#xff1a; 第一部分&#xff08;简介&#xff09;&#xff1a;企业架构的关键概念&#xff0c;特别是 TOGAF 方法进行了概要介绍第二部分&#xff08;架构开发方法&#xff09;&#xff1a; TOGAF 框架的核心部分。描述了 TOGAF 架构开发方法&…

爪哇,我初学乍道

>>上一篇&#xff08;学校上课&#xff0c;是耽误我学习了。。&#xff09; 2016年9月&#xff0c;我大二了。 自从我发现上课会耽误我学习&#xff0c;只要我认为不影响我期末学分的&#xff0c;我就逃课了。 绝大多数课都是要签到的&#xff0c;有的是老师突击喊名字…