《TCP/IP网络编程》(第十三章)多种I/O函数(2)

使用readvwritev函数可以提高数据通信的效率,它们的功能可以概括为**“对数据进行整合传输及发送”**。
即使用writev函数可以将分散在多个缓冲中的数据一并发送,使用readv函数可以由多个缓冲分别接受,所以适当使用他们可以减少I/O函数的调用次数。

1.readvwritev函数

readv()函数
用于从文件描述符中读取数据,并存储在多个缓冲区中

ssize_t readv(
int fd, //文件描述符。
const struct iovec *iov, //指向 iovec 结构体数组的指针,iovec 结构体定义了一个缓冲区。
int iovcnt//iovec 结构体数组的元素个数。
);

//iovec 结构体
struct iovec {
    void *iov_base; //指向缓冲区的起始地址(基地址)
    size_t iov_len; //缓冲区的长度,即需要传输的字节数
};

示例代码

#include<stdio.h>
#include<sys/uio.h>
#define BUF_SIZE 100
int main(int argc, char *argv[])
{
	struct iovec vec[2];
    char buf1[BUF_SIZE] = {0, };
    char buf2[BUF_SIZE] = {0, };
    int str_len;
	//设置两个缓存区,第一个存储5个字节,剩下的给第二个缓冲区
    vec[0].iov_base = buf1;
    vec[0].iov_len = 5;
    vec[1].iov_base = buf2;
    vec[1].iov_len = BUF_SIZE;

    str_len = readv(0, vec, 2);//第一个参数是0,即接受键盘输入
    printf("Read total bytes: %d \n", str_len);
    printf("First message: %s \n", buf1);
    printf("Second message: %s \n", buf2);
    return 0;
}

在这里插入图片描述

writev()函数
用于将多个缓冲区中的数据写入文件描述符,这种方法称为“聚集写”或“向量写”。

ssize_t writev(
int fd, //文件描述符
const struct iovec *iov, //指向 iovec 结构体数组的指针,iovec 结构体定义了一个缓冲区。
int iovcnt//iovec 结构体数组的元素个数。
);

//iovec 结构体
struct iovec {
    void *iov_base; //指向缓冲区的起始地址(基地址)
    size_t iov_len; //缓冲区的长度,即需要传输的字节数
};

示例代码

#include<stdio.h>
#include<sys/uio.h>

int main(int argc, char *argv[]){
    struct iovec vec[2];
    //有两个缓冲
    char buf1[] = "1234567890";
    char buf2[] = "ABCDEFGHIJ";
    int str_len;

    vec[0].iov_base = buf1;
    vec[0].iov_len = 10;
    vec[1].iov_base = buf2;
    vec[1].iov_len = 10;
    str_len = writev(1, vec, 2);//第一个参数是1,所以是向控制台输出
    puts("");
    printf("writev bytes: %d \n", str_len);
}

在这里插入图片描述

2.在Windows中实现紧急消息机制

在《TCP/IP网络编程》(第十三章)多种I/O函数(1)中已经基于Linux平台实现了MSG_OOB机制,但是是基于Linux的信号处理机制,所以无法直接移植到Windows平台。

若要在Windows平台上实现该机制,则需要通过select()函数,该函数简介参考《TCP/IP网络编程》(第十二章)I/O复用(1)

PS:MSG_OOB在select()监视下会被视为异常数据
发送端代码

#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>

#define BUFSIZE 30
void ErrorHandling(char* message);

int main(int argc, char* argv[]){
    WSADATA wsa;
    SOCKET hSocket;
    SOCKADDR_IN sendAddr;

    if(argc!=3){
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }

    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0){
        ErrorHandling("WSAStartup() error!");
    }
    hSocket = socket(PF_INET, SOCK_STREAM, 0);
    memset(&sendAddr, 0, sizeof(sendAddr));
    sendAddr.sin_family = AF_INET;
    sendAddr.sin_addr.s_addr = inet_addr(argv[1]);
    sendAddr.sin_port = htons(atoi(argv[2]));

    if(connect(hSocket, (SOCKADDR*)&sendAddr, sizeof(sendAddr)) == SOCKET_ERROR)
        ErrorHandling("connect() error!");
    
    send(hSocket, "123", 3, 0);
    send(hSocket, "4", 1, MSG_OOB);//带外数据在select的监视中,会被视为异常数据
    send(hSocket, "567", 3, 0);
    send(hSocket, "890", 3, MSG_OOB);//只把最后一个字节0作为紧急信息发送

    closesocket(hSocket);
    WSACleanup();
    return 0;
}

void ErrorHandling(char* message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

接受端代码

#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>


#define BUFSIZE 30
void ErrorHandling(char *);

int main(int argc, char *argv[]){
    WSADATA wsa;
    SOCKET hAcptSock, hRecvSock;
    SOCKADDR_IN sendAdr, recvAdr;
    int sendAdrSz,strLen;
    char buf[BUFSIZE];
    int result;

    fd_set read,except,read_copy,except_copy;
    struct timeval timeout;

    if(argc != 2){
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0)
        ErrorHandling("WSAStartup() error!");
    
    hAcptSock = socket(PF_INET, SOCK_STREAM, 0);
    if(hAcptSock == INVALID_SOCKET)
        ErrorHandling("socket() error");
        
    memset(&recvAdr, 0, sizeof(recvAdr));
    recvAdr.sin_family = AF_INET;
    recvAdr.sin_addr.s_addr = htonl(INADDR_ANY);
    recvAdr.sin_port = htons(atoi(argv[1]));

    if(bind(hAcptSock, (SOCKADDR*)&recvAdr, sizeof(recvAdr)) == SOCKET_ERROR)
        ErrorHandling("bind() error");

    if(listen(hAcptSock, 5) == SOCKET_ERROR)
        ErrorHandling("listen() error");

    sendAdrSz = sizeof(sendAdr);
    hRecvSock = accept(hAcptSock, (SOCKADDR*)&sendAdr, &sendAdrSz);
    FD_ZERO(&read);    // 清空reads集合
    FD_ZERO(&except);  // 清空except集合
    FD_SET(hRecvSock, &read);		// 将套接字添加到reads集合
    FD_SET(hRecvSock, &except);		// 将套接字添加到except集合
    while(1){
        read_copy = read;
        except_copy = except;
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        result = select(0, &read_copy, 0, &except_copy, &timeout);//开始监视文件描可读数集和与异常集合
        if(result>0){
            if(FD_ISSET(hRecvSock, &except_copy)){
            //使用FD_ISSET宏检查套接字是否在异常集合中。
            //如果是,表示发生了异常事件,此时会调用recv函数并指定MSG_OOB标志来接收带外数据
                strLen = recv(hRecvSock, buf, BUFSIZE-1, MSG_OOB);
                buf[strLen] = 0;
                printf("urgent message: %s \n", buf);
            }

            if(FD_ISSET(hRecvSock, &read_copy)){// 如果检测到读事件
                strLen = recv(hRecvSock, buf, BUFSIZE-1, 0);
                if(strLen == 0){
                    break;
                    closesocket(hRecvSock);
                }else{
                    buf[strLen] = 0;
                    printf("normal message: %s", buf);
                }
            }
        }
    }
    closesocket(hAcptSock);
    closesocket(hRecvSock);
    WSACleanup();
    return 0;
}

void ErrorHandling(char *message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

在这里插入图片描述
优先接受MSG_OOB信息4和0。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Refused to load the stylesheet问题解决方案

今天项目部署的过程中遇到一个安全策略问题的报错&#xff0c;大概意思就是处于安全考虑&#xff0c;不允许src外链其他不安全的静态文件 解决这种问题的一个思路大概就是找到index.html文件先看下是否存在 <meta http-equiv"Content-Security-Policy" content&…

用PlayCanvas打造一个令人惊叹的3D图在线展示

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 PlayCanvas实例化渲染&#xff1a;大规模渲染优化 应用场景 在游戏开发中&#xff0c;经常需要渲染大量相同或相似模型。传统方法需要为每个模型创建单独的渲染对象&#xff0c;这会消耗大量内存和GPU资源。实…

问你为什么选择Kafka,你会怎么回答?

可靠的含义在百度百科的解释是&#xff1a;可以信赖、可以相信、可靠的朋友。那Kafka究竟是不是一个可靠的朋友呢&#xff1f;既然全世界绝大部分高可用系统都有Kafka的支持&#xff0c;Kafka必定有其过人之处&#xff0c;跟着我来分析分析。 另外多提一嘴Kafka在GitHub目前已…

【AIGC X UML 落地】通过多智能体实现自然语言绘制UML图

前天写了篇博文讲到用PlantUML来绘制C类图和流程图。后台有读者留言&#xff0c;问这步能否自动化生成&#xff0c;不想学习 PlantUML 语法。 我想了下&#xff0c;发现这事可行&#xff0c;确实可以做到通过自然语言的描述就能实现 UML图的绘制&#xff0c;昨天晚上加了个班到…

安装TPMmanager

sudo apt-get install qt4-qmake sudo apt-get install libqt4-dev下载TPMManager&#xff0c;解压之后拖入Ubuntu&#xff0c;进入目录 https://gitcode.com/Rohde-Schwarz/TPMManager/overview?utm_sourcecsdn_github_accelerator&isLogin1 cd tpmmanager-master qmake…

快速排序(Quick Sort)(C语言) 超详细解析!!!

生活的本质是什么呢? 无非就是你要什么就不给你什么. 而生活的智慧是什么呢? 是给你什么就用好什么. ---马斯克 索引 一. 前言二. 快速排序的概念三. 快速排序的实现1. hoare2. 挖坑法3. 前后指针法 总结 正文开始 一. 前言 接上文, 前面我们了解了插入排序, 与优化版本希尔…

Vulnhub-DC-2

靶机IP:192.168.20.135 网络有问题的可以看下搭建Vulnhub靶机网络问题(获取不到IP) kaliIP:192.168.20.128 扫描靶机端口及服务版本 发现开放了80和7744端口 并且是wordpress建站 dirsearch扫描目录 访问前端界面&#xff0c;发现存在重定向 在hosts文件中增加192.168.2…

【UML用户指南】-09-对基本结构建模-类图

目录 1、概述 2、引入 3、过程 4、常用建模技术 4.1、对简单协作建模 4.2、对逻辑数据库模式建模 4.3、正向工程 1、概述 类图是面向对象系统建模中最常见的图。 类图显示一组类、接口、协作以及它们之间的关系 类图用于对系统静态设计视图建模。其大多数涉及到对系统的…

这个世界,对于心态好的人,就是个大游乐场,越刺激越好玩。对于胆小鬼,那就是地狱,随时随地都会受伤

心态决定你的世界&#xff1a;游乐场还是地狱 在这个充满变数的世界里&#xff0c;我们的心态决定了我们看待世界的方式。对于心态积极的人来说&#xff0c;世界就像一个巨大的游乐场&#xff0c;每一个挑战都是一个新的游戏&#xff0c;每一个刺激都是乐趣的一部分。而对于那…

纷享销客安全体系: 组织及人员安全

组织及人员安全是纷享销客安全战略中的重要组成部分。 我们致力于确保组织内部和员工的安全&#xff0c;并采取一系列措施来预防和应对安全威胁。我们将持续改进和更新安全措施&#xff0c;以适应不断变化的威胁环境&#xff0c;并确保组织和员工的安全意识和培训得到充分关注…

鹧鸪云设计系统:太阳能光伏发电设计图纸绘制全攻略

随着全球对可持续能源的需求不断增加&#xff0c;越来越多的人开始关注太阳能发电技术。对于初学者来说&#xff0c;掌握一套有效的太阳能光伏发电设计图纸至关重要。本为了实现这一目标&#xff0c;鹧鸪云设计系统的出现为初学者的电站图纸绘制降低了难度。 接下来&#xff0c…

微信小程序uniapp的父子之间的通信传递

1.父传递给子信息 my-test是子组件 demo是父组件 这是定义在父组件中的的info信息 要将这个传递给子组件 子组件在properties 中接收父组件传递来的数据 msg type 是类型 value是默认值&#xff0c;当父组件没有传递数据时&#xff0c;就会默认使用value的数据 子组件…

STM32 音乐播放器之音频入门实验(pwm、dac、.wav、.mp3)

1.pwm实现简易电子琴实验 1.改变PWM频率&#xff0c;输出不同音调 2.改变占空比&#xff0c;调节音量大小 3.按键弹奏&#xff0c;支持按按键录取弹奏音 4.播放:中高低音&#xff1b;录取音&#xff1b;指定歌曲 5.支持按上一首&#xff0c;下一首&#xff0c;调弹奏速度&#…

To C道路越走越夯实,1688彻底变身了?

在偌大的电商市场&#xff0c;消费者都是专业的“掘宝者”&#xff0c;热衷于发现各种新奇商品和采购新通路。 拼多多、1688等平台也正是在这种情况下&#xff0c;成为消费市场的“宠儿”。其中&#xff0c;1688的发展路径较为独特&#xff0c;据天眼查&#xff0c;其为源头厂…

springboot大学生就业管理系统-计算机毕业设计源码89344

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对大学生就业管理系统等问题&#xff0c;对大…

【Linux取经路】信号的发送与保存

文章目录 一、重新理解发送信号二、信号的保存、阻塞信号的概念三、信号集操作函数3.1 sigprocmask3.2 sigpending 四、阻塞信号代码验证五、结语 一、重新理解发送信号 进程通过位图来实现对普通信号&#xff08;1-31号信号&#xff09;的保存&#xff0c;该位图保存在进程的…

TikTok广告投放攻略——广告类型详解

TikTok广告是品牌或创作者付费向特定目标受众展示的推广内容&#xff08;通常是全屏视频&#xff09;。TikTok 上的广告是一种社交媒体营销形式&#xff0c;通常旨在提高广告商的知名度或销售特定产品或服务。 就 TikTok广告投放而言&#xff0c;其组织层级分为三个层级&#x…

数据库基本知识

感觉面试的时候面试官大多数都必问数据库&#xff0c;也可以理解&#xff0c;企业肯定会涉及到大规模数据存储&#xff0c;那么数据库存储就一定会用到数据库。做一些数据库相关的基本知识总结&#xff0c;持续更新~ 【死锁专题】 1.如何解决数据库并发造成的安全问题&#x…

【LeetCode 滑动窗口】LC_3_无重复字符的最长子串

文章目录 1. 无重复字符的最长子串 1. 无重复字符的最长子串 题目链接&#x1f517; &#x1f34e;题目思路&#xff1a;&#x1f427;① 滑动窗口的思想&#xff1b;&#x1f427;② 用什么来维护窗口呢 &#xff1f; 用 双指针 和 unordered_set来维护&#xff0c;为什么呢…

从 LangChain 中学习检索增强

前言 之前讲了一些关于 RAG 的使用技巧和经验&#xff0c;今天我们提供两个进阶版的文本切分和检索的方法&#xff0c;希望对你有所帮助。以下两种方法取自 LangChain 的官方示例&#xff0c;感兴趣也可以直接去阅读官方文档。 一、父文档检索 Parent Document Retriever 当…