TCP/IP网络编程 第十五章:套接字和标准I/O
标准I/O函数的优点
标准I/O函数的两个优点
将标准I/O函数用于数据通信并非难事。但仅掌握函数使用方法并没有太大意义,至少应该
了解这些函数具有的优点。下面列出的是标准I/O函数的两大优点:
□标准I/O函数具有良好的移植性(Portability)
□标准I/O函数可以利用缓冲提高性能。
关于移植性无需过多解释。不仅是IO函数,所有标准函数具有良好的移植性。因为,为了支持所有操作系统(编译器),这些函数都是按照ANSI C标准定义的。当然,这并不局限于网络编程,而是适用于所有编程领域。
接下来讨论标准I/O函数的第二个优点。使用标准IO函数时会得到额外的缓冲支持。这种表达方式也许会带来一些混乱,因为之前讲过,创建套接字时操作系统会准备I/O缓冲。造成更大混乱之前,先说明这两种缓冲之间的关系。创建套接字时,操作系统将生成用于I/O的缓冲。此缓冲在执行TCP协议时发挥着非常重要的作用。此时若使用标准IO函数,将得到额外的另一缓冲的支持。大概意思如下图所示:
从图中可以看到,使用标准I/O函数传输数据时,经过两个缓冲。例如,通过fputs函数传输字符串“Hello”时,首先将数据传递到标准IO函数的缓冲。然后数据将移动到套接字输出缓冲,最后将字符串发送到对方主机。
既然知道了两个缓冲的关系,接下来再说明各自的用途。设置缓冲的主要目的是为了提高性能,但套接字中的缓冲主要是为了实现TCP协议而设立的。例如,TCP传输中丢失数据时将再次传递
,而再次发送数据则意味着在某地保存了数据。存在什么地方呢?套接字的输出缓冲。与之
相反,使用标准IO函数缓冲的主要目的是为提高性能,但是实际上,缓冲并非在所有情况下都能带来卓越的性能。但需要传输的数据越多,有无缓冲带来的性能差异越大。可以通过如下两种角度说明性能的提高。
□传输的数据量
□数据向输出缓冲移动的次数
比较1个字节的数据发送10次(10个数据包)的情况和累计10个字节发送1次的情况。发送数据时使用的数据包中含有头信息(首部)。头信息与数据大小无关,是按照一定的格式填入的。即使假设该头信息占用40个字节(实际更大),需要传递的数据量也存在较大差别。
□1个字节10次40×10=400字节
□10个字节1次40x1=40字节
另外,为了发送数据,向套接字输出缓冲移动数据也会消耗不少时间。但这同样与移动次数
有关。1个字节数据共移动10次花费的时间将近10个字节数据移动1次花费时间的10倍。
标准I/O函数的几个缺点
如果就此结束说明,各位可能认为标准I/O函数只有优点。其实它同样有缺点,整理如下。
□不容易进行双向通信。
□有时可能频繁调用fflush函数。(用以刷新缓冲区)
□需要以FILE结构体指针的形式返回文件描述符。
假设各位已掌握了C语言中的绝大部分文件IO相关知识。打开文件时,如果希望同时进行读写操作,则应以r+、w+、a+模式打开。但因为缓冲的缘故,每次切换读写工作状态时应调用fflush函数。这也会影响基于缓冲的性能提高。而且,为了使用标准IO函数,需要FILE结构体指针(以下简称“FILE指针”)。而创建套接字时默认返回文件描述符,因此需要将文件描述符转化为FILE指针。
使用标准I/O函数
如前所述,创建套接字时返回文件描述符,而为了使用标准IO函数,只能将其转换为FILE
结构体指针。先介绍其转换方法。
利用fdopen函数转换为FILE结构体指针
可以通过fdopen函数将创建套接字时返回的文件描述符转换为标准IO函数中使用的FILE结
构体指针。
#include<stdio.h>
FILE * fdopen(int fildes, const char * mode);
//成功时返回转换的FILE结构体指针,失败时返回NULL。fildes //需要转换的文件描述符。mode //将要创建的FILE结构体指针的模式(mode)信息。
上述函数的第二个参数与fopen函数中的打开模式相同。常用的参数有读模式"r"和写模式"w"。
利用fileno函数转化为文件描述符
接下来介绍与fdopen函数提供功能相反的函数,该函数在有些情况下非常好用。
#include<stdio.h>
int fileno(FILE * stream);//成功时返回转化后的文件描述符,失败时返回-1
此函数的用法也非常简单,向该函数传递FILE指针参数时返回相应文件描述符。
基于套接字的标准I/O函数使用
前面介绍了标准IO函数的优缺点,同时介绍了文件描述符转换为FILE指针的方法。下面将其适用于套接字。虽然是套接字操作,但并没有需要另外说明的内容,只需简单应用这些函数。接下来将之前的回声服务器端和客户端改为基于标准IO函数的数据交换形式。
无论是服务器端还是客户喘,更改方式并无差异。只需调用fdopen函数并使用标准IO函数,
相信各位也能自行更改。首先给出更改后的服务器端代码。
#include<"头文件声明和之前章节中的回声服务端相同,故省略">
#define BUF_SIZE 30
void error_handling(char *message);int main(int argc,char *argv[]){int serv_sock,clnt_sock;char message[BUF_SIZE];int str_len,i;struct sockaddr_in serv_addr;struct sockaddr_in clnt_addr;socklen_t clnt_addr_sz;FILE * readfp;FILE * writefp;if(argc!=2){printf("Usage : %s <port>\n",argv[0]);exit(1);}serv_sock=socket(PF_INET,SOCK_STREAM,0);if(serv_sock==-1)error_handling("socket() error");memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);serv_addr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)error_handling("bind() error");if(listen(serv_sock,5)==-1)error_handling("listen() error");clnt_addr_sz=sizeof(clnt_sock);for(int i=0;i<5;++i){clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_sock,&clnt_addr_sz);if(clnt_sock==-1)error_handling("accept() error");else printf("Connected client %d \n",i+1);readfp=fdopen(clnt_sock,"r");writefp=fdopen(clnt_sock,"w");while(!feof(readfp)){fgets(message,BUF_SIZE,readfp); fputs(message,writefp);fflush(writefp);}fclose(readfp);fclose(writefp);}close(serv_sock);return 0;
}void error_handling(char*message){//与之前章节的错误处理函数相同,故省略
}
接下来给出回声客户端代码
#include<"与之前章节的头文件声明相同,故省略">
#define BUF_SIZE 1024
void error_handling(char *message);int main(int argc,char *argv[]){int sock;char message[BUF_SIZE];int str_len;struct sockaddr_int serv_addr;FILE * readfp;FILE * writefp;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;serv_addr.sin_addr.s_addr=inet_addr(argv[1]);serv_addr.sin_port=htons(atoi(argv[2]));if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)error_handling("connect() error");elseputs("Connected.......");readfp=fdopen(sock,"r");writefp=fdopen(sock,"w");while(1){fputs("Input message(Q to quite):",stdout);fgets(message,BUF_SIZE,stdin);if(!strcmp(message,"q\n")||!strcmp(message,"Q\n"))break;fputs(message,writefp);fflush(writefp);fgets(message,BUF_SIZE,readfp);printf("Message from server: %s",message);}fclose(writefp);fclose(readfp);return 0;
}void error_handling(char *message){//和前面章节的错误处理函数相同,故省略。
}
以上就是标准IO函数在套接字编程中的应用方法,因为需要编写额外的代码,所以并不像想象中那么常用。但某些情况下也是非常有用的,而且可以再次复习标准IO函数,对大家也非常有益。
相关文章:

TCP/IP网络编程 第十五章:套接字和标准I/O
标准I/O函数的优点 标准I/O函数的两个优点 将标准I/O函数用于数据通信并非难事。但仅掌握函数使用方法并没有太大意义,至少应该 了解这些函数具有的优点。下面列出的是标准I/O函数的两大优点: □标准I/O函数具有良好的移植性(Portability) □标准I/O函数可以利用缓…...

SaleSmartly,客户满意度调查的绝对好助手
企业使用客户满意度调查来收集反馈并评估客户满意度水平,包括有关产品质量、服务、支持和整体满意度的问题。客户满意度调查的主要目标是直接从客户那里收集有价值的见解,以了解他们的需求、偏好和期望。这种反馈可以帮助企业确定需要改进的领域…...

MySQL高阶语句
文章目录 一.常用查询1.按关键字排序(ORDER BY 语句)1.1 语法格式1.2 ASC和DESC的排序概念1.3 举例1.3.1 数据库有一张info表,记录了学生的id,姓名,分数,地址和爱好1.3.2 按分数排序,默认不指定…...

手机快充协议
高通:QC2.0、QC3.0、QC3.5、QC4.0、QC5.0、 FCP、SCP、AFC、SFCP、 MTKPE1.1/PE2.0/PE3.0、TYPEC、PD2.0、PD3.0/3.1、VOOC 支持 PD3.0/PD2.0 支持 QC3.0/QC2.0 支持 AFC 支持 FCP 支持 PE2.0/PE1.1 联发科的PE(Pump Express)/PE 支持 SFCP 在PP…...
centos 7升级gcc到10.5.0
目录 1、安装gcc 1.1、查看是否含有gcc及gcc版本 1.2、快速安装gcc 2、升级gcc 2.1、下载gcc源码包并解压缩 2.2、下载编译依赖项 2.3、新建gcc-bulid目录(与gcc-10.5.0同级)并进入该目录中 2.4、生成Makefile文件 2.5、开始编译 2.6、安装 2…...
从脚手架搭建到部署访问路程梳理
1、vue-cli 起文件: 2、配置 webpack :打包配置等,env文件( 处理线上和测试的ip), https://www.ibashu.cn/news/show_377892.html 3、样式:封装 style :组件(element-u…...

数据库应用:MySQL数据库SQL高级语句与操作
目录 一、理论 1.克隆表与清空表 2.SQL高级语句 3.SQL函数 4.SQL高级操作 5.MySQL中6种常见的约束 二、实验 1.克隆表与清空表 2.SQL高级语句 3.SQL函数 4.SQL高级操作 5.主键表和外键表 三、总结 一、理论 1.克隆表与清空表 克隆表:将数据表的数据记录…...
xshell连接WSL2
1. 卸载 ssh server sudo apt-get remove openssh-server2. 安装 ssh server sudo apt-get install openssh-server3. 修改 ssh server 配置 sudo vim /etc/ssh/sshd_config需要修改以下几项: Port 2222 #默认的是22,但是windows有自己的ssh服务&am…...

Flask新手教程
Flask简介 Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。 Flask 可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或…...

拼多多API接口,百亿补贴商品详情页面采集
电商API的数据类型 电商API提供的数据种类多样,一般可分为以下几类: 1.商品数据:商品ID、商品名称、商品价格、库存等。 2.交易数据:订单号、付款时间、收货人等。 3.店铺数据:店铺ID、店铺名称、开店时间、店铺评…...
C++入门(未完待续)
1.命名空间 使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染 定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员 ①.普通的命名空间 n…...
Python爬虫学习笔记(四)————XPath解析
目录 0.xpath最新下载地址和安装教程 1.xpath安装 2.xpath基本使用 3.xpath基本语法 4.实例 (1)xpath解析本地文件 (2)xpath解析服务器响应的数据 ①获取百度网站的“百度一下”四个字 ②获取站长素材网站情侣图片前十页的…...

知识图谱推理的学习逻辑规则(上)
知识图谱推理的学习逻辑规则 摘要介绍相关工作模型知识图谱推理逻辑规则概率形式化参数化优化 实验实验设置实验结果 结论 原文: 摘要 本文研究了在知识图谱上进行推理的学习逻辑规则。 逻辑规则用于预测时提供了可解释性并且可以推广到其他任务中,因…...

【从零开始学习C++ | 第二十一篇】C++新增特性 (上)
目录 前言: 委托构造函数: 类内初始化: 空指针: 枚举类: 总结: 前言: C的学习难度大,内容繁多。因此我们要及时掌握C的各种特性,因此我们更新本篇文章,向…...

你真的会用async和await么?
背景 背景就是遇到了一个比较烦人的模块,里面的涉及到了大量的async 和 awiat。发现大多人对这个语法糖一知半解,然后大量的滥用,整理一下 async 前置知识: Promise.resolve(foo) new Promise(resolve > resolve(foo)…...

vscode远程连接提示:过程试图写入的管道不存在(删除C:\Users\<用户名>\.ssh\known_hosts然后重新连接)
文章目录 复现过程原因解决方法总结 复现过程 我是在windows上用vscode远程连接到我的ubuntu虚拟机上,后来我的虚拟机出了点问题,我把它回退了,然后再连接就出现了这个问题 原因 本地的known_hosts文件记录服务器信息与现服务器的信息冲突了…...

【005】基于深度学习的图像语 通信系统
摘要 语义通信是一种新颖的通信方式,可通过传输数据的语义信息提高带宽效率。提出一种用于无线图像传输的系统。该系统基于深度学习技术开发并以端到端(E2E)的方式进行训练。利用深度学习实现语义特征的提取和重建,在发送端提取信…...

基于ssm的社区生活超市的设计与实现
博主介绍:专注于Java技术领域和毕业项目实战。专注于计算机毕设开发、定制、文档编写指导等,对软件开发具有浓厚的兴趣,工作之余喜欢钻研技术,关注IT技术的发展趋势,感谢大家的关注与支持。 技术交流和部署相关看文章…...

长短期记忆网络(LSTM)原理解析
长短期记忆网络(Long Short-Term Memory,简称LSTM)是一种常用于处理序列数据的深度学习模型。它在循环神经网络(Recurrent Neural Network,RNN)的基础上进行了改进,旨在解决传统RNN中的梯度消失…...

vscode debug的方式
在.vscode文件夹下建立launch.json 例子1:调试python 来自 https://github.com/chunleili/tiPBD/tree/amg {"version": "0.2.0","configurations": [{"name": "hpbd 5 5","type": "python&quo…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...

如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...