llinux C语言在网络编程时使用标准IO

目录

fdopen(3)函数

使用标准IO发送数据

使用标准IO接收数据

注意


先看一个简单的TCP客户端程序:

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>int main(void){int fd = socket(AF_INET, SOCK_STREAM, 0);if(fd == -1){perror("socket");exit(1);}struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8000);addr.sin_addr.s_addr = inet_addr("192.168.1.14");if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1){perror("connect");exit(1);}// 准备写入char message[] = "Hello World!";char *buf = message;int ret, len;len = strlen(message);while(len != 0 && (ret = write(fd, buf, len)) != 0){if(ret == -1){if(errno == EINTR) continue; // 写入时收到信号,可以重新写入perror("write");break;}len -= ret;buf += ret;}close(fd);return 0;
}

可以看到,在发送信息时,使用了这样的代码:

    char message[] = "Hello World!";char *buf = message;int ret, len;len = strlen(message);while(len != 0 && (ret = write(fd, buf, len)) != 0){if(ret == -1){if(errno == EINTR) continue; // 写入时收到信号,可以重新写入perror("write");break;}len -= ret;buf += ret;}

这是因为,使用write(2)函数时,可能会出现写入不全的情况(部分写),因此,需要通过while循环,确保它能全部写完。

但是,这样的代码太麻烦了,有没有简单的办法? 

fdopen(3)函数

我们知道,在标准IO中,有一个fdopen(3)函数:

#include <stdio.h>
FILE *fdopen(int fd, const char *mode);

这个函数将会把一个文件描述符转换成一个文件指针。参数中,fd是文件描述符,mode是操作模式,如"r+"。可以设置为"w"或"w+",但不会清空文件。如果把socket(2)函数返回的文件描述符改成文件指针,就可以通过fprintf等方法直接输出了。

使用标准IO发送数据

我们可以修改代码如下:

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdlib.h>int main(void){int fd = socket(AF_INET, SOCK_STREAM, 0);if(fd == -1){perror("socket");exit(1);}struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8000);addr.sin_addr.s_addr = inet_addr("192.168.1.14");if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1){perror("connect");exit(1);}FILE *fp = fdopen(fd, "r+");fprintf(fp, "Hello World!");fclose(fp);return 0;
}

可以看到,采用标准IO,代码就简单了很多。而且,使用标准IO,也可以避免操作底层的时候出现一些问题(如部分写)

我们可以用网络调试助手看一下使用了这种方法是否可以正常发送:

可以看到,它能够正常发送数据,并正常关闭套接字。

使用标准IO接收数据

我们还可以让它能够读取数据:

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdlib.h>int main(void){int fd = socket(AF_INET, SOCK_STREAM, 0);if(fd == -1){perror("socket");exit(1);}struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8000);addr.sin_addr.s_addr = inet_addr("192.168.1.14");if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1){perror("connect");exit(1);}FILE *fp = fdopen(fd, "r+");char buf[1024];fgets(buf, 1024, fp);printf("data is %s\n", buf);fclose(fp);return 0;
}

 使用网络调试助手发送数据(注意要在数据后面加入换行符):

终端输出:

data is Hello Client.

注意

标准IO的设计主要是为了文件读写,将其应用与网络编程并不总是最佳选择。另外需要注意,使用了fdopen(3)函数后,不应直接操作文件描述符(虽然这是合法的),这可能会导致数据竞争等未定义行为。

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

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

相关文章

哈尔滨华时信息公司是怎么样帮助社会残障人士解决生活保障

在社会进步的今天&#xff0c;关注弱势群体的生活保障问题显得尤为重要。哈尔滨华时信息公司积极响应社会责任&#xff0c;通过多项举措&#xff0c;为社会残障人士提供生活保障&#xff0c;助力他们融入社会、享受尊严生活。 1. 提供就业机会&#xff1a; 华时信息公司积极招…

以题为例浅谈DFS算法

DFS算法是什么 深度优先搜索算法(Depth First Search 简称DFS算法)&#xff0c;一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点&#xff0c;尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件&#xff0c;搜索将回溯到发现节点v的…

php彩虹/异世界云商全解系统

系统更新与修复列表 1. 基于彩虹的二次开发 - 对彩虹系统进行了二次开发&#xff0c;增强了系统的功能和性能。2. 新增自定义输入框提示内容&#xff08;支持批量修改&#xff09; - 用户可以自定义输入框的提示内容&#xff0c;并支持批量修改&#xff0c;提升用户体验。3. 新…

Spring Boot+Vue前后端分离项目如何部署到服务器

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

IO流(1)——文件输入输出流(FIleInputStream、FIleOutputStream)

IO流概述 IO流应用场景 FileInputStream&#xff08;文件字节输入流&#xff09; 方法 使用read&#xff08;&#xff09;每次读取一个字节的弊端 使用read&#xff08;byte[] buffer&#xff09;方法每次读取多个字节&#xff0c;取多少&#xff0c;倒多少 解决方法 文件字节…

C++ 开发篇+一个简单的数据库管理系统ZDB

说明&#xff1a;本文供数据库爱好者和初级开发人员学习使用 标签&#xff1a;数据库管理系统、RDBMS、小程序、C、C程序 系统&#xff1a;Windows 11 x86 CPU &#xff1a;Intel IDE &#xff1a;Visual Studio 2022 语言&#xff1a;C语言 标准&#xff1a;C14 提示&#xff…

在idea中配置tomcat服务器,部署一个项目(下载教程加链接)

第一步&#xff1a;把Tomcat下载好 ww​​​​​​​Apache Tomcat - Welcome! 链接如上&#xff1a;进去后在左边找到Tomcat8点击进去后 找到图下内容 第二步&#xff1a; 打开这个文件点击bin进去 会出现一个黑色框框&#xff0c;也就是服务器 完成后就可以在浏览器输入…

掘根宝典之C++普通迭代器和反向迭代器详解

简介 迭代器是一种用于遍历容器元素的对象。它提供了一种统一的访问方式&#xff0c;使程序员可以对容器中的元素进行逐个访问和操作&#xff0c;而不需要了解容器的内部实现细节。 C标准库里每个容器都定义了迭代器&#xff0c;这迭代器的名字就叫容器迭代器 迭代器的作用类…

Yolo系列算法-理论部分-YOLOv1

0. 紧接上一篇目标检测算法的介绍 基于深度学习的目标检测算法概述-CSDN博客 本篇YOLO算法系列&#xff0c;参考优秀作者-AI菌&#xff0c;文章链接&#xff1a;YOLO系列算法精讲&#xff1a;从yolov1至yolov8的进阶之路&#xff08;2万字超全整理&#xff09;_yolov9-CSDN博…

deepin23beta中SQLite3数据库安装与使用

SQLite 是一个嵌入式 SQL 数据库引擎&#xff0c;它实现了一个自包含、无服务器、零配置、事务性 SQL 数据库引擎。 SQLite 的代码属于公共领域&#xff0c;因此可以免费用于任何商业或私人目的。 SQLite 是世界上部署最广泛的数据库&#xff0c;其应用程序数量之多&#xff0c…

HarmonyOS应用开发-Stage模型开发概述

基本概念 UI框架 HarmonyOS提供了一套UI开发框架&#xff0c;即方舟开发框架&#xff08;ArkUI框架&#xff09;。提供了应用UI开发所必需的能力&#xff1a;多种组件、布局计算、动画能力、UI交互、绘制。 方舟开发框架针对开发者提供了两种开发范式&#xff1a; 基于ArkTS…

STM32-位带操作及位带别名区

这里写自定义目录标题 一、位带操作的基本含义及作用二、以STM32为例三、位带别名区和位带区(寄存器地址位地址)的转换关系四、使用例程 一、位带操作的基本含义及作用 位带别名区的设计主要是为了**方便对位带区单个比特位进行读写操作**。在某些应用场景下&#xff0c;需要频…