热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

网络编程——分离I/O流

参考《TCPIP网络编程》尹圣雨分离IO流两种IO流分离第一种是TCPIO过程分离。这种方法通过调用fork函数复制出1个文件描述符,以区分输入和输出中使用的

参考


  1. 《TCP/IP网络编程》 尹圣雨

分离I/O流


两种I/O流分离

第一种是TCP I/O过程分离。这种方法通过调用fork函数复制出1个文件描述符,以区分输入和输出中使用的文件描述符。虽然文件描述符本身不会根据输入和输出进行区分,但分开了2个文件描述符的用途,因此也属于流的分离。

第二种是使用标准I/O函数时,通过2次fdopen函数的调用,创建读模式FILE指针和写模式FILE指针,分离了输入工具和输出工具,也可以视为流的分离。

分离流的好处

第一种分离流的方式的好处:

  1. 通过分开输入过程(代码)和输出过程降低实现难度
  2. 与输入无关的输出操作可以提高速度

第二种分离流的方式的好处:

  1. 为了将FILE指针按读模式和写模式区分
  2. 可以通过区分读写模式降低实现难度
  3. 通过区分I/O缓冲提高缓冲性能

分离流带来的EOF问题

第一种分离流的方式没有问题,但是第二种分离流的方式有问题。

虽然表面上看可以针对输出模式的FILE指针调用fclose函数,向对方传递EOF,编程可以接收数据但无法发送数据的半关闭状态,但实际上,fclose(writefp)完全终止了套接字,而不是半关闭。

终止流时无法半关闭的原因:读模式FILE指针和写模式FILE指针都是基于同一文件描述符创建的。因此,针对任意一个FILE指针调用fclose函数时都会关闭文件描述符,也就终止套接字。

文件描述符的复制和半关闭

为了实现可以输入但无法输出的半关闭状态,创建FILE指针前先复制文件描述符即可。然后,利用各自的文件描述符生成读模式FILE指针和写模式FILE指针。因为,销毁所有文件描述符后才能销毁套接字。即针对写模式FILE指针调用fclose函数,只能销毁与该FILE指针相关的文件描述符,无法销毁套接字。

但实际上,剩余的与读模式FILE指针相关的文件描述符还是可以同时进行I/O,因此,仅仅如此还不能实现半关闭。还需要使用shutdown函数。

复制文件描述符

与fork函数不同,调用fork函数将复制整个进程,因此同一进程内不能同时有原件和副本。如果在同一进程内完成文件描述符的复制,需要dup或dup2函数。

#include int dup(int fildes);
int dup2(int fildes, int fildes2);

成功时返回复制的文件描述符,失败时返回-1。其中,fildes为需要复制的文件描述符,fildes为明确指定的文件描述符整数值。dup2函数明确指定复制的文件描述符整数值,向其传递大于0且小于进程能生成的最大文件描述符值时,该值将成为复制出的文件描述符值。

复制文件描述符后进行流的分类

我们的目标是,通过服务器端的半关闭状态接收客户端最后发送的字符串。为了完成这样任务,服务器端需要同时发送EOF。

需要注意的是,无论复制出了多少文件描述符,均应调用shutdown函数发送EOF并进入半关闭状态,因此代码中shutdown(fileno(writefp), SHUT_WR);实现了服务器的半关闭状态,并向客户端发送EOF

#include
#include
#include
#include
#include
#include #define BUF_SIZE 1024int main(int argc, char* argv[])
{int serv_sock, clnt_sock;FILE* readfp;FILE* writefp;struct sockaddr_in serv_adr, clnt_adr;socklen_t clnt_adr_sz;char buf[BUF_SIZE] = {0,};serv_sock = socket(PF_INET, SOCK_STREAM, 0);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(atol(argv[1]));bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr));listen(serv_sock, 5);clnt_adr_sz = sizeof(clnt_adr);clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);readfp = fdopen(clnt_sock, "r");writefp = fdopen(dup(clnt_sock), "w"); // 利用dup函数的返回值生成FILE指针fputs("FROM SERVER: Hi~ client? \n", writefp);fputs("I love all of the world \n", writefp);fputs("You are awesome! \n", writefp);fflush(writefp);shutdown(fileno(writefp), SHUT_WR); // 针对fileno函数返回的文件描述符调用shutdown函数fclose(writefp);fgets(buf, sizeof(buf), readfp);fputs(buf, stdout);fclose(readfp);return 0;
}


推荐阅读
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
author-avatar
手机用户2502903715
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有