《TCP IP 网络编程》第十五章

第 15 章 套接字和标准I/O

15.1 标准 I/O 的优点

 标准 I/O 函数的两个优点:

        除了使用 read 和 write 函数收发数据外,还能使用标准 I/O 函数收发数据。下面是标准 I/O 函数的两个优点:

  • 标准 I/O 函数具有良好的移植性
  • 标准 I/O 函数可以利用缓冲提高性能

        创建套接字时,操作系统会准备 I/O 缓冲。此缓冲在执行 TCP 协议时发挥着非常重要的作用。此时若使用标准 I/O 函数,将得到额外的缓冲支持。如下图:

        假设使用 fputs 函数进行传输字符串 「Hello」时,首先将数据传递到标准 I/O 缓冲,然后将数据移动到套接字输出缓冲,最后将字符串发送到对方主机

        设置缓冲的主要目的是为了提高性能。从以下两点可以说明性能的提高:

  • 传输的数据量。
  • 数据向输出缓冲移动的次数。

        比较 1 个字节的数据发送 10 次的情况和 10 个字节发送 1 次的情况。发送数据时,数据包中含有头信息。头信与数据大小无关,是按照一定的格式填入的。假设头信息占 40 个字节,需要传输的数据量也存在较大区别:       

        1 个字节 10 次:40*10=400 字节。

        10个字节 1 次:40*1=40 字节。

        另外,为了发送数据,向套接字输出缓冲移动数据也会消耗不少时间。但这同样与移动次数有关。1个字节数据共移动10次花费的时间将近10个字节数据移动1次花费时间的10倍。

标准 I/O 函数和系统函数之间的性能对比:

        基于read&write函数的文件复制程序:

#include <stdio.h>
#include <fcntl.h>
#define BUF_SIZE 3

int main(int argc, char *argv[])
{
    int fd1, fd2;
    int len;
    char buf[BUF_SIZE];

    fd1 = open("news.txt", O_RDONLY);
    fd2 = open("cpy.txt", O_WRONLY | O_CREAT | O_TRUNC);

    while ((len = read(fd1, buf, sizeof(buf))) > 0)
        write(fd2, buf, len);

    close(fd1);
    close(fd2);

    return 0;
}

         采用标注I/O函数复制文件:

#include <stdio.h>
#define BUF_SZIE 3

int main(int argc, char *argv[])
{
    FILE *fp1;
    FILE *fp2;
    char buf[BUF_SZIE];

    fp1 = open("news.txt", "r");
    fp2 = open("cpy.txt", "w");

    while (fgets(buf, BUF_SZIE, fp1) != NULL)
        fputs(buf, fp2);
    fclose(fp1);
    fclose(fp2);
    return 0;
}

         对以上两种示例测试,基于标注I/O函数的示例运行得更快。

标准 I/O 函数的几个缺点:

        标准 I/O 函数存在以下几个缺点:

  • 不容易进行双向通信。
  • 有时可能频繁调用 fflush 函数。
  • 需要以 FILE 结构体指针的形式返回文件描述符。

15.2 使用标准 I/O 函数

利用 fdopen 函数转换为 FILE 结构体指针:

        函数原型如下:

#include <stdio.h>
FILE *fdopen(int fildes, const char *mode);
/*
成功时返回转换的 FILE 结构体指针,失败时返回 NULL
fildes : 需要转换的文件描述符
mode : 将要创建的 FILE 结构体指针的模式信息
*/

        示例:

#include <stdio.h>
#include <fcntl.h>

int main()
{
    FILE *fp;
    int fd = open("data.dat", O_WRONLY | O_CREAT | O_TRUNC); //创建文件并返回文件描述符
    if (fd == -1)
    {
        fputs("file open error", stdout);
        return -1;
    }
    fp = fdopen(fd, "w"); //返回 写 模式的 FILE 指针
    fputs("NetWork C programming \n", fp);
    fclose(fp);
    return 0;
}

         运行结果:

        文件描述符转换为 FILE 指针,并可以通过该指针调用标准 I/O 函数。 

利用 fileno 函数转换为文件描述符:

        该函数与fdopen函数提供相反功能,函数原型如下:

#include <stdio.h>
int fileno(FILE *stream);
/*
成功时返回文件描述符,失败时返回 -1
*/
#include <stdio.h>
#include <fcntl.h>

int main()
{
    FILE *fp;
    int fd = open("data.dat", O_WRONLY | O_CREAT | O_TRUNC);
    if (fd == -1)
    {
        fputs("file open error");
        return -1;
    }

    printf("First file descriptor : %d \n", fd);
    fp = fdopen(fd, "w"); //转成 file 指针
    fputs("TCP/IP SOCKET PROGRAMMING \n", fp);
    printf("Second file descriptor: %d \n", fileno(fp)); //转回文件描述符
    fclose(fp);
    return 0;
}

        运行结果:

         输出的文件描述符值相同,证明fileno函数正确转换了文件描述符。

15.3 基于套接字的标准 I/O 函数使用

        把第四章的回声客户端和回声服务端的内容改为基于标准 I/O 函数的数据交换形式:

客户端:

#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;
    char message[BUF_SIZE];
    int str_len;
    struct sockaddr_in serv_adr;
    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_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_adr.sin_port = htons(atoi(argv[2]));

    if (connect(sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) == -1)
        error_handling("connect() error!");
    else
        puts("Connected...........");
    readfp = fdopen(sock, "r");
    writefp = fdopen(sock, "w");
    while (1)
    {
        fputs("Input message(Q to quit): ", 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)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(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 serv_sock, clnt_sock;
    char message[BUF_SIZE];
    int str_len, i;

    struct sockaddr_in serv_adr, clnt_adr;
    socklen_t clnt_adr_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_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));

    if (bind(serv_sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) == -1)
        error_handling("bind() error");

    if (listen(serv_sock, 5) == -1)
        error_handling("listen() error");

    clnt_adr_sz = sizeof(clnt_adr);
    //调用 5 次 accept 函数,共为 5 个客户端提供服务
    for (i = 0; i < 5; i++)
    {
        clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &clnt_adr_sz);
        if (clnt_sock == -1)
            error_handling("accept() error");
        else
            printf("Connect 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)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

运行实例:

        可以看出,运行结果和第四章相同,这是利用标准 I/O 实现的。 


习题:

1、请说明标准 I/O 的 2 个优点。他为何拥有这 2 个优点?

        ①具有很高的移植性②有良好的缓冲提高性能。

 

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

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

相关文章

基于 FFlogs API 快速实现的 logs 颜色查询小爬虫

文章目录 找到接口解析响应需要平均颜色和过本次数&#xff1f; 找到接口 首先试了一下爬虫&#xff0c;发现和wow一样官网上有暴露的 API&#xff0c;链接在&#xff1a;FFlogs v1 API 文档链接 通过查询官方提供的 API 接口得知&#xff1a; user_name 角色名字 api_key …

Django Rest_Framework(一)

1. Web应用模式 在开发Web应用中&#xff0c;有两种应用模式&#xff1a; 前后端不分离[客户端看到的内容和所有界面效果都是由服务端提供出来的。] 前后端分离【把前端的界面效果(html&#xff0c;css&#xff0c;js分离到另一个服务端或另一个目录下&#xff0c;python服务…

翻转卡片游戏(力扣)

题目 在桌子上有 n 张卡片&#xff0c;每张卡片的正面和背面都写着一个正数&#xff08;正面与背面上的数有可能不一样&#xff09;。 我们可以先翻转任意张卡片&#xff0c;然后选择其中一张卡片。 如果选中的那张卡片背面的数字 x 与任意一张卡片的正面的数字都不同&#…

YOLOV8改进:更换PoolFormer主干网络

1.该文章属于YOLOV5/YOLOV7/YOLOV8改进专栏,包含大量的改进方式,主要以2023年的最新文章和2022年的文章提出改进方式。 2.提供更加详细的改进方法,如将注意力机制添加到网络的不同位置,便于做实验,也可以当做论文的创新点。 2.涨点效果:添加PoolFormer主干,有效涨点。 论…

C++共享数据的保护

虽然数据隐藏保护了数据的安全性&#xff0c;但各种形式的数据共享却又不同程度地破坏了数据的安全。因此&#xff0c;对于既需要共享有需要防止改变的数据应该声明为常量。因为常量在程序运行期间不可改变&#xff0c;所以可以有效保护数据。 1.常对象 常对象&#xff1a;它…

硬盘的分类

目前常见的硬盘种类主要有以下2种&#xff1a; 机械硬盘&#xff08;HDD&#xff09; 机械硬盘&#xff08;HDD&#xff09;是一种利用旋转磁盘和读写头来存储和访问数据的存储设备。它由磁盘、读写头、电机和控制电路等组成&#xff0c;磁盘通常是一种铝合金或玻璃材质的圆盘&…

ELK日志分析系统

文章目录 一. ELK日志分析系统概述1.ELK 简介2.ELK日志分析系统2.1 ElasticSearch2.1.1 ElasticSearch概述2.1.2 ElasticSearch核心概念&#xff08;作用&#xff09; 2.2 Kiabana2.2.1 Kiabana 概念2.2.2 Kiabana 主要功能 2.3 Logstash2.3.1 Logstash 概念2.3.2 Logstash主要…

在 TDosCommand 组件中执行多个命令

在 TDosCommand 组件中执行多个命令可以通过在命令行中使用“&&”或“&”符号来实现。其中&#xff0c;“&&”符号表示前一个命令执行成功后才会执行下一个命令&#xff0c;“&”符号表示前一个命令执行完成后立即执行下一个命令。下面是一个示例程序&…

开源项目-知识库管理系统(中国软件杯项目)

简述 哈喽,大家好,今天带来一个开源项目-知识库管理系统,项目通过Spring MVC技术实现。通过readme了解到这是某位大神大三暑假(2016年)参加第五届中国软件杯项目的源码。由三人团队完成(Yu yufeng\Zhou changqin\Liu chenzhe) 此作品获得了本科组全国二等奖。项目本身用…

GD32F103VE点灯

GD32F103VE点灯主要用来学习端口引脚的输出配置。它由LED.c&#xff0c;LED.h&#xff0c;SoftDelay.c和main.c组成。 #include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t #include "SoftDelay.h"#include …

git面试题

文章目录 git经常用哪些指令git出现代码冲突怎么解决你们团队是怎么管理git分支的如何实现Git的免密操作 git经常用哪些指令 产生代码库 新建一个git代码库 git init下载远程项目和它的整个代码历史 git clone 远程仓库地址配置 显示配置 git config --list [--global]编辑配置…

实验笔记之——Windows下的Android环境开发搭建

好久一段时间没有进行Android开发了&#xff0c;最新在用的电脑也没有了Android studio了。为此&#xff0c;本博文记录一下最近重新搭建Android开发的过程。本博文仅为本人学习记录用&#xff08;**别看&#xff09; 目录 安装Android Studio以及JDK JDK Android Studiio …

网工必须掌握的5种组网技术,你会了吗?

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、VLAN技术 1、VLAN是什么&#xff1f; 2、VLAN的作用 ①提高网络安全性 ②提高了网络的灵活性性 ③增强了网络的健壮性 二、D…

基于ASP.NET MVC开发的、开源的个人博客系统

推荐一个功能丰富、易于使用和扩展的开源博客&#xff0c;可以轻松地创建和管理自己的博客。 项目简介 基于.Net Framework 4.5开发的、开源博客系统&#xff0c;具有丰富的功能&#xff0c;包括文章发布、分类、标签、评论、订阅、统计等功能&#xff0c;同时也可以根据需要…

深度学习之tensorboard可视化工具

(1)什么是tensorboard tensorboard是TensorFlow 的一个可视化工具包&#xff0c;提供机器学习实验所需的可视化和工具&#xff0c;该工具的功能如下&#xff1a; 跟踪和可视化指标&#xff0c;例如损失和精度可视化模型图&#xff08;操作和层&#xff09;查看权重、偏差或其…

docker-compose 搭建 Sharding-Proxy 5.4.0 分库分表代理服务

感谢: 程序员一枚 提供搭建方式 项目地址: https://gitee.com/dromara/RuoYi-Cloud-Plus/tree/2.X/ 1.在 mysql 创建两个库 创建两个库 data-center_0 data-center_1 分别执行如何sql CREATE TABLE t_order_0 (order_id bigint(20) UNSIGNED NOT NULL COMMENT 主键ID,user_…

python3GUI--我的翻译器By:PyQt5(附下载地址)

文章目录 一&#xff0e;前言二&#xff0e;展示1.主界面2.段落翻译3.单词翻译 三&#xff0e;设计1.UI设计2.软件设计3.参考 四&#xff0e;总结 一&#xff0e;前言 很早之前写过一篇python3GUI–翻译器By:PyQt5&#xff08;附源码&#xff09; &#xff0c;但是发现相关引擎…

JVM-运行时数据区

目录 什么是运行时数据区&#xff1f; 方法区 堆 程序计数器 虚拟机栈 局部变量表 操作数栈 动态连接 运行时常量池 方法返回地址 附加信息 本地方法栈 总结&#xff1a; 什么是运行时数据区&#xff1f; Java虚拟机在执行Java程序时&#xff0c;将它管…

张量Tensor 深度学习

1 张量的定义 张量tensor理论是数学的一个分支学科&#xff0c;在力学中有重要的应用。张量这一术语源于力学&#xff0c;最初是用来表示弹性介质中各点应力状态的&#xff0c;后来张量理论发展成为力学和物理学的一个有力数学工具。 张量&#xff08;Tensor&#xff09;是一个…

6.s081(Fall 2022)Lab2: system calls

文章目录 前言其他篇章参考链接0. 前置准备1. System call tracing (moderate) 前言 好像没啥前言 其他篇章 环境搭建 Lab1:Utilities 参考链接 官网链接 xv6手册链接&#xff0c;这个挺重要的&#xff0c;建议做lab之前最好读一读。 xv6手册中文版&#xff0c;这是几位先…