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

news2024/11/24 8:42:01

使用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。

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

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

相关文章

Pytorch 实现目标检测一(Pytorch 23)

一 目标检测和边界框 在图像分类任务中&#xff0c;我们假设图像中只有一个主要物体对象&#xff0c;我们只关注如何识别其类别。然而&#xff0c;很多时候图像里有多个我们感兴趣的目标&#xff0c;我们不仅想知 道它们的类别&#xff0c;还想得到它们在图像中的具体位置。在…

ESP8266+STM32+阿里云保姆级教程(AT指令+MQTT)

前言&#xff1a;在开发过程中&#xff0c;几乎踩便了所有大坑小坑总结出的文章&#xff0c;我是把坑踩满了&#xff0c;帮助更过小白快速上手&#xff0c;如有错误之处&#xff0c;还麻烦各位大佬帮忙指正、 目录 一、ESP-01s介绍 1、ESP-01s管脚功能&#xff1a; 模组启动模…

vscode 突然无法启动 WSL terminal 了怎么办?

参考&#xff1a;https://github.com/microsoft/vscode/issues/107485 根据参考网页&#xff0c;似乎在 windows 更新之后&#xff0c;重启&#xff0c;就有可能出现标题所说的 vscode 无法启动 WSL terminal 的情况。 首先使用 cmd 进入 wsl 终端&#xff0c;把 ~/.vscode-se…

EON安装ASE Interface

EON安装 我的eon路径于/eon/。 则环境为 export PYTHONPATH/eon/:$PYTHONPATH export PATH/eon/bin:$PATHsource: https://theory.cm.utexas.edu/eon/installation.html ASE 测试系统ubuntu。如果你python2和python3总是纠缠不清&#xff0c;可以sudo apt install python-…

vscode中执行python语句dir(torch)不返回结果

输入半天&#xff0c;发现在IDLE运行后的shell界面输入语句就会返回一大串。但是在vscode中老是不返回值。 结果恍然发现这没加print&#xff08;&#xff09;。 无语惨了。 家人们&#xff0c;这是python&#xff0c;而不是matlab。思维还没转换过来&#xff0c;笑死

扩散模型Stable Diffusion

扩散模型构成 Text Encoder(CLIPText) Clip Text为文本编码器。以77 token为输入&#xff0c;输出为77 token 嵌入向量&#xff0c;每个向量有768维度。 Diffusion(UNetScheduler) 在潜在空间中逐步处理扩散信息。以文本嵌入向量和由噪声组成的起始多维数组为输入&#xff0c…

二叉树—leetcode

前言 本篇博客我们来仔细说一下二叉树二叉树的一些OJ题目 请看完上一篇&#xff1a;数据结构-二叉树-CSDN博客 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;LeetCode_普通young man的博客-CSDN博客 若有问题 评论区见&#x1f4dd; &…

Zynq7000 系列FPGA模块化仪器

• 基于 XilinxXC7Z020 / 010 / 007S • 灵活的模块组合 • 易于嵌入的紧凑型外观结构 • 高性能的 ARM Cortex 处理器 • 成熟的 FPGA 可编程逻辑 &#xff0c;基于 IP 核的软件库 FPGA 控制器 Zynq7000 系列模块是基于 Xilinx XC7Z020/010/007S 全可编程片上系统 (SoC) 的…

LLM的基础模型8:深入注意力机制

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则提…

[ue5]建模场景学习笔记(5)——必修内容可交互的地形,交互沙(3)

1.需求分析&#xff1a; 我们现在已经能够让这片地形出现在任意地方&#xff0c;只要角色走在这片地形上&#xff0c;就能够产生痕迹&#xff0c;但这片区域总是需要人工指定&#xff0c;又无法把这片区域无限扩大&#xff08;显存爆炸&#xff09;&#xff0c;因此尝试使角色无…

【BUG】已解决:Could not find a version that satisfies the requirement tensorflow

已解决&#xff1a;Could not find a version that satisfies the requirement tensorflow 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;同时是武汉城市开发者社区主理人 擅长.net、C…

Java抽象队列同步器AQS

AQS介绍 AQS是一个抽象类&#xff0c;主要用来构建锁和同步器。 public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { }AQS为构建锁和同步器提供了一些通用功能的实现&#xff0c;因此&#xff0c;使用…

基于STM32开发的智能语音助理系统

⬇帮大家整理了单片机的资料 包括stm32的项目合集【源码开发文档】 点击下方蓝字即可领取&#xff0c;感谢支持&#xff01;⬇ 点击领取更多嵌入式详细资料 问题讨论&#xff0c;stm32的资料领取可以私信&#xff01; 目录 引言环境准备智能语音助理系统基础代码实现&#xff…

BFS实现图的点的层次-java

加强对广度优先搜索的理解&#xff0c;其实就是主要的3个步骤&#xff0c;外加数组模拟单链表是基础&#xff0c;要搞懂。 目录 前言 一、图中点的层次 二、算法思路 1.广度优先遍历 2.算法思路 三、代码如下 1.代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入…

【Python教程】2-函数、逻辑运算与条件判断

在整理自己的笔记的时候发现了当年学习python时候整理的笔记&#xff0c;稍微整理一下&#xff0c;分享出来&#xff0c;方便记录和查看吧。个人觉得如果想简单了解一名语言或者技术&#xff0c;最简单的方式就是通过菜鸟教程去学习一下。今后会从python开始重新更新&#xff0…

0基础学习区块链技术——入门

大纲 区块链构成区块链相关技术Hash算法区块链区块链交易 参考资料 本文力求简单&#xff0c;不讨论任何技术细节&#xff0c;只是从简单的组成来介绍区块链技术&#xff0c;以方便大家快速入门。同时借助一些可视化工具&#xff0c;辅助大家有直观的认识。 区块链构成 顾名思…

一文掌握Vue3:深度解读Vue3新特性、Vue2与Vue3核心差异以及Vue2到Vue3转型迭代迁移重点梳理与实战

每次技术革新均推动着应用性能与开发体验的提升。Vue3 的迭代进步体现在性能优化、API重构与增强型TypeScript支持等方面&#xff0c;从而实现更高效开发、更优运行表现&#xff0c;促使升级成为保持竞争力与跟进现代前端趋势的必然选择。本文深度解读Vue3 响应式数据data、生命…

④-1单细胞学习-cellchat单数据代码补充版

目录 1&#xff0c;数据输入及处理 ①载入包和数据 ②CellChat输入数据准备 ③构建CellChat对象 ④数据预处理 2&#xff0c;细胞通讯预测 ①计算细胞通讯概率 ②提取配受体对细胞通讯结果表 ③提取信号通路水平的细胞通讯表 ④细胞互作关系可视化 1&#xff09;细胞…

服务器部署spring项目jar包使用bat文件,省略每次输入java -jar了

echo off set pathC:\Program Files\Java\jre1.8.0_191\bin START "YiXiangZhengHe-8516" "%path%/java" -Xdebug -jar -Dspring.profiles.activeprod -Dserver.port8516 YiXiangZhengHe-0.0.1-SNAPSHOT.jar 将set path后面改成jre的bin文件夹 START 后…

数据:人工智能的基石 | Scale AI 创始人兼 CEO 亚历山大·王的创业故事与行业洞见

引言 在人工智能领域&#xff0c;数据被誉为“新石油”&#xff0c;其重要性不言而喻。随着GPT-4的问世&#xff0c;AI技术迎来了新的浪潮。众多年轻创业者纷纷投身这一领域&#xff0c;Scale AI的创始人兼CEO亚历山大王&#xff08;Alexander Wang&#xff09;就是其中的佼佼…