我所不知道的TCP Socket编程(五)-交换数据、套接字读写操作

2023-11-09

五:交换数据

     

已经建立了服务器和客户端的链接,现在需要让它们进行数据交换;

     

     你可以将TCP连接想象成一串连接了本地套接字和远程套接字的管子,我们可以沿着这个管子发送和接受数据;

     实际中,数据被编码为TCP/IP分组,经过多台路由器和主机,抵达终点;

     

     5.1 流:

     

     TCP具有流性质:

     TCP是一个基于流的协议,这也是创建套接字时,传入的:STREAM选项的意思;

     

     前面提到了分组,从协议层面上而言,TCP在网络上发送的就是分组;

     从代码的角度来说,TCP连接提供了一个不间断的,有序的通信流;

     

     比如,你可以在客户端发送3分数据,一次一份,在服务端一次操作(当做一份数据)就可以读取全部数据;

     

     即,流并没有消息边界(流中内容的次序还是会保留的);

     

     5.2 套接字读操作

     

     介绍各种读取数据的方式以及各自的使用场景;

     

     5.2.1 简单的读操作

     

     从套接字读取数据的最简单方法是使用read:

     

     # ./code/snippets/read.rb
     require 'socket'
     Socket.tcp_server_loop(4481) do | connection |
        # 从连接中读取数据的最简单方法
        puts connection.read
        # 完成读取之后关闭连接,让客户端知道不用在等待数据返回
        connection.close
     end

     

     服务端开始侦听4481端口,此时可以使用netcat命令,连接本地localhost 4481端口

     

     echo gekko | nc localhost 4481
     

     (没有运行Ruby程序,在终端做了简单测试,查看输出结果)(图1)

     



     Ruby中所有的IO对象(套接字、管道、文件……)都有一套通用的接口,支持read,write,flush等方法;

     底层的read(2)、write(2)等系统调用都可以作用于文件、套接字、管道等之上;这种抽象源自操作系统本身,记住,一切皆文件;

     

     5.2.2 没那么简单

     

     如果运行的是如下命令:

     

     tail -f /var/log/system.log | nc -t 127.0.0.1 4481
     

     然后不管了,服务器将永远不会停止读取数据;(图2)



     

     原因是EOF(end-of-file),之后会介绍;

     

     问题在于tail -f根本就不会停止发送数据;如果tail没有数据可以发送,他会一直等到有为止;这使得netcat的管道一直处于打开状态;

     

     服务器的read调用就一直被阻塞着,直到客户端发送完数据为止;服务器等待的过程中,会将收到的数据缓冲起来,不返回给应用程序;

     

     5.2.3 读取长度

     

     作为上述问题的一个不太成熟的解决方式:指定最小的读取长度;

     这样就不用等到客户端结束发送才停止读取,而是告诉服务器读取(read)特定的数据量;     


    # ./code/snippets/read.rb
     require 'socket'
     one_kb = 1024 # 字节数
     Socket.tcp_server_loop(4481) do | connection |
        # 以1kb为单位进行读取
        while data = connection.read(one_kb) do
            puts data
        end
        connection.close
     end

     

     然后再运行:


     tail -f /var/log/system.log | nc -t 127.0.0.1 4481

     会使服务器以1kb为单位打印数据;

     

     这个例子中给read传递了一个参数:他告诉read在读取了一定数量的数据之后就停止读取并返回;

     由于希望得到所有可用的数据,我们在调用read方法时使用了循环,直到它不再返回数据为止;

     (在《iOS平台Socket编程实践》系列文章中,演示了相关的数据传输)

     

     注:

     请注意区分一个概念,无论是服务器还是客户端(一对多的关系)都只是Socket连接的端点,由于是一对多的关系,对应的Socket链接也将是多个,虽然iOS中,CocoaAsyncSocket把他们封装成了一个类,但请注意区分;

     

     5.2.4 阻塞的本质

     

     read调用会一直阻塞,知道获取了完整的长度(full length)的数据为止;

     上面的例子有个问题,就是如果读取了若干次之后的数据不足1kb,那么read会一直阻塞;

     如此会导致死锁,可以采用的补救措施:

     1)客户端发送了500B后就再发送一个EOF;

     2)服务器采用部分读取(partial read)的方式;

          

     5.2.5 EOF事件

     

     当调用read并受到EOF时,就意味着不再有数据,可以停止读取了;(对于理解IO很重要)

     EOF代表一个状态事件,shutdown和close都会导致一个EOF事件被发送给另一端进行读操作的进程,这样他就知道不会在有数据到达了;

     

     下面是正确的数据读取代码:

     

     # ./code/snippets/read.rb
     require 'socket'
     one_kb = 1024 # 字节数
     Socket.tcp_server_loop(4481) do | connection |
     # 以1kb为单位进行读取
     while data = connection.read(one_kb) do
     puts data
     end
     connection.close
     end

     

     客户端连接:

     

     # ./code/snippets/read.rb
     require 'socket'
     
     client = TCPSocket.new('localhost' , 4481)
     client.write('gekko')
     client.close

     

     5.2.6 部分读取

     

     即readpartial;

     readpartial并不会阻塞,而是立刻返回可用数据;调用时,需要传入整数参数,指定最大长度(readpartial最多读取到指定长度);

     指定读取1kb,但只发送500B的话,readpartial不会阻塞,而是会立刻返回已经读取到的数据;

     

     服务端:

     

     # ./code/snippets/readpartial_with_length.rb
     require 'socket'
     one_hundred_kb = 1024 * 100
     Socket.tcp_server_loop(4481) do | connection |
        begin
            # 每次读取100KB或更少
            while data = connection.readpartial(one_hundred_kb) do
                puts data
            end
        rescue EOFError
        end
        
        connection.close
     end

     

     这样,只要有数据,readpartial就会将其返回,即便是小于最大长度;

     

     EOF而言,read仅仅是返回,readpartial则会产生一个EOFError异常,提醒我们小心;

     

     总结就是:

     read很懒惰,只会傻等,以求返回尽可能多的数据;

     readpartial更勤快,只要有数据可用就立刻返回;

     

     在学习缓冲区之后,我们会对一次性读取多少数据,小读取量多次和大读取量单次那个更好等问题做出回答;

     

     5.3 套接字写操作

     

     write方法:

     

     # ./code/snippets/readpartial_with_length.rb
     require 'socket'
     
     Socket.tcp_server_loop(4481) do | connection |
        # 向连接中写入数据的最简单方式
        connection.write('Welcome!')
        connection.close
     end


     5.4 涉及到的系统调用

     

     ·Socket#read->read(2)                   //ri Socket#read -> man 2 read

     ·Socket#readpartial->read(2)            //ri Socket#readpartial -> man 2 read

     ·Socket#write->write(2)                   //ri Socket#write -> man 2 write


     总结:

        下一节将会介绍几个较高级的概念,不过到目前为止,我所不知道的Socket已经没那么多了,你的呢。


     

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我所不知道的TCP Socket编程(五)-交换数据、套接字读写操作 的相关文章

  • vertx 内的多线程

    我是 vert x 的新手 我正在尝试 vert x NetServer 功能 http vertx io core manual java html writing tcp servers and clients http vertx i
  • TCP 数据偶尔会以错误的顺序接收且不完整

    我用 Java 创建了 TCP 服务器应用程序 并用 C 创建了客户端应用程序 当我发送数据时 客户端有时会乱序接收数据 有时部分会完全丢失 基本上 我在服务器 java 中使用的代码如下 已删除 ServerSocket welcomeS
  • Spring Integration TCP - 在发送数据之前启动消息握手

    我正在使用 MessagingGateway 将数据发送到服务器 我为出站网关配置了 AbstractClientConnectionFactory 和 ServiceActivator 为了将数据发送到我的服务器 我需要在启动连接时发送握
  • WebSocket 和纯 TCP 之间的根本区别是什么?

    我读过关于WebSockets http en wikipedia org wiki Web Sockets我想知道为什么浏览器不能像任何其他桌面应用程序一样简单地打开简单的 TCP 连接并与服务器通信 为什么可以通过 websocket
  • WCF TCP 客户端 - 如何使用它们的基本指南?

    我有一个 WCF 服务并希望使用 TCP 绑定连接到它 这一切都很好 但是你应该如何处理客户呢 我注意到 如果您为每个调用创建一个新客户端 它不会重新使用该通道 并会留下一堆 TCP 连接 直到超时 创建客户端 调用其方法 然后关闭它是正常
  • TCPServer 具有同时全双工通信

    我正在尝试编写一个 C 服务器 客户端 它将同时通过 TCP 相互发送字节数组 我正在努力思考如何实现这一目标 我见过的所有示例都等待消息 然后发送响应 我需要同时进行沟通 我是否需要为服务器和客户端上的传入和传出创建 2 个单独的 TCP
  • 用 C 处理 TCP 的部分返回

    我一直在读Beej 的网络编程指南 http beej us guide bgnet 获取 TCP 连接的句柄 在其中一个示例中 简单 TCP 流客户端的客户端代码如下所示 if numbytes recv sockfd buf MAXDA
  • Python。从 6 字节字符串中打印 mac 地址

    我有 6 字节字符串的 mac 地址 您将如何以 人类 可读的格式打印它 Thanks import struct x x x x x x struct unpack BBBBBB your variable with mac
  • 如何将我的 Kivy 客户端连接到服务器(TCP、套接字)

    因此 作为我的项目 2D 多人纸牌游戏 的一部分 我已经弄清楚如何在线托管和运行服务器脚本 我的计划是让两个单独的 kivy 客户端连接到服务器 这只是一个带有命令的脚本 但是我对操作顺序有些困惑 因为我think客户端连接可能与消息循环发
  • 如何识别用户空间和内核空间之间的特定套接字?

    我在用户空间中有一个库 可以拦截套接字层调用 例如socket connect accept 等等 我只处理 TCP 套接字 在内核空间中 我有一个网络内核模块 它处理所有 TCP 连接 我需要能够在驱动程序中识别哪些套接字被用户空间库拦截
  • 无法通过 ngrok ssh 进入远程 Linux

    远程Linux计算机位于内部网络中 没有公共IP地址 所以我安装了ngrok ngrok tcp 22 ngrok by inconshreveable Ctrl C 退出 在线隧道状态版本2 0 19 2 0 17网页界面http 127
  • Nodejs TCP连接客户端端口分配

    我使用nodejs在客户端和服务器之间创建了tcp连接 网络模块 https nodejs org api net html 服务器正在侦听已经预定义的端口 并且客户端正在连接到该端口 据我了解客户端的端口是由节点动态分配的 那是对的吗 节
  • 是什么导致 MSSQL 中出现“非阻塞套接字上的操作将阻塞”错误?

    错误 异常查询为 CREATE NONCLUSTERED INDEX I1 ON AllAccounts BAK Master received Day ASC 出现异常 发生一个或多个错误 错误 异常内部异常无法从传输连接读取数据 非阻塞
  • Node.js 找不到模块“tcp”

    节点在以下行崩溃 var tcp require tcp 错误文本 node js 201 throw e process nextTick error or error event on first tick Error Cannot f
  • 如何模拟 TCP/IP 错误?

    在多层应用程序上 我需要模拟各种 TCP IP 错误来测试一些重新连接代码 有谁知道我可以使用什么工具 基于 Windows 来实现此目的 谢谢 Scapy http secdev org projects scapy 允许您控制数据包的各
  • 如何在java应用程序中检测FIN - tcp标志?

    我在两台计算机之间有持久的 TCP 连接 第二台计算机不受我的控制 第二台计算机可以随时发送FIN标志 并且首先必须关闭当前连接 将FIN标志发送回第二台计算机 我如何知道第二台计算机正在发送 FIN 标志 以及何时必须调用 Java 应用
  • Python套接字模块:Recv()数据响应被切断

    解释 我目前正在尝试使用 python 脚本控制智能电源板 为了实现这一点 我使用了带有套接字模块的 TCP 连接 大约 75 的情况下 我会得到我正在寻找的响应 数据 并且一切都运行良好 然而 大约 25 的情况下 响应会以完全相同的长度
  • C# Socket.receive连续接收0字节且循环中不阻塞

    我正在尝试用 C 编写一个最简单的多线程 TCP 服务器 它接收来自多个客户端的数据 每次连接新客户端时 都会建立套接字连接 并将套接字作为参数传递给新类函数 之后运行 while 循环并接收数据 直到客户端连接为止 这里的问题是 sock
  • 简单的跨平台 TCP IP API?

    我不打算使用像 QT 或 wxWidgets 的 API 这样的大东西 我只想要可以在 Android iOS Windows Mac Linux 上运行的简单套接字 我正在制作一个事件驱动的纸牌游戏 所以 TCP 是最好的 本质上 我只想
  • 为什么 UDP 服务器中只有一个套接字?

    我正在准备考试 发现了这个问题 典型的 UDP 服务器可以使用单个套接字来实现 解释一下为什么 对于 TCP 驱动的服务器 我发现创建了两个套接字 一个用于所有客户端访问服务器 另一个用于每个客户端的特定 套接字 用于服务器和客户端之间的进

随机推荐

  • 网页在线视频下载教程(m3u8格式介绍及下载教程)

    简介 m3u8文件是苹果公司使用的HTTP Live Streaming HLS 协议格式的基础 HLS是新一代流媒体传输协议 其基本实现原理为将一个大的媒体文件进行分片 将该分片文件资源路径记录与m3u8文件 即playlist 内 其中
  • android studio Flutter开发好用的插件

    Dart 必备 Flutter 必备 Flutter Enhancement Suite Flutter代码增强提示 WidgetGenerator 自动生成Widget接口 flutter img sync 自动同步照片路径
  • Hibernate 超简单的一对多和多对一查询

    这里使用的Teacher类和Student类 假设一个Teacher对应多个学生 一个学生对应一个老师 所需jar包 开始建表 1 表名 teacher 2 表名 student 主键都为自增长 创建实体类 Teacher类 package
  • 论文阅读——Temporal Convolutional Attention-based Network For Sequence Modeling

    https arxiv org pdf 2002 12530 pdf 代码 https github com haohy TCAN 用于序列建模的基于注意力的时序卷积网络 作者提出一种时序卷积注意力网络 Temporal Convoluti
  • shell 遍历当前目录以及所有子目录下文件

    bin bash file count 0 folder count 0 function TRAVEL ALL FILE for file in do if f file then normal file echo file file c
  • 干货分享

    如今 随着诸如互联网以及物联网等技术的不断发展 越来越多的数据被生产出来 据统计 每天大约有超过2 5亿亿字节的各种各样数据产生 这些数据需要被存储起来并且能够被方便的分析和利用 随着大数据技术的不断更新和迭代 数据管理工具得到了飞速的发展
  • OpenGL学习——(3)库函数

    1 定义视口 void ChangeSize int w int h glViewport 0 0 w h 代表窗口中视口的左下角坐标是 0 0 通常都是0 0 w和h用像素表示 在窗口改变大小时接收新的宽和高 glViewport主要完成
  • 实战:NodeLocal DNSCache安装-2023.2.23(测试成功)

    实战 NodeLocal DNSCache安装 2023 2 24 测试成功 目录 文章目录 实战 NodeLocal DNSCache安装 2023 2 24 测试成功 目录 本节实战 实验环境 实验软件 0 部署前dns测试 1 获取资
  • Brew的安装路径

    Homebrew 将本机的 usr local 目录初始化为Git的工作树 并将目录所有者变更为 USER 也就是你当前所操作的用户 所以以后的操作都不再需要sudo 这是安全的 全新的OS X默认是没有该目录的 也就是说该目录并非是系统所
  • 图形界面操作pandas:计算变异系数(极差 四分位差 方差 标准差 协方差 变异系数)

    昨天 freepy增加了计算离散程度功能 包括极差 四分位差 方差 标准差 协方差 变异系数 其中 协方差需要指定两个字段 部分运行结果 df apple stock Open 极差 691 29 df apple stock High 四
  • sklearn中fit_transform,transform和fit函数的区别和作用详解

    写在前面 fit和transform没有任何关系 仅仅是数据处理的两个不同环节 之所以出来fit transform这个函数名 仅仅是为了写代码方便 会高效一点 sklearn里的封装好的各种算法使用前都要fit fit相对于整个代码而言
  • 简单使用iPhone自带视频播放器

    利用苹果自带的视频播放器播放视频 在调用方法前 我们需要包含头文件 import
  • 生成测试数据神器:使用python的faker库

    一 faker是啥 Faker是一个Python包 开源的GITHUB项目 主要用来生成大量的伪数据 使用Faker包 无需再手动生成或者手写随机数来生成数据 只需要调用Faker提供的方法 即可完成数据的生成 二 Faker的使用 引用包
  • electron --unsafely-treat-insecure-origin-as-secure 问题解决 navigator.mediaDevices = undefined

    问题原因 由于electron mainWindow loadURL http 127 0 0 1 访问是已http协议 而chrome浏览器在访问http请求时考虑隐私安全是无法打开许多Web API的 如 navigator media
  • 求字符串可匹配的最大长度

    如 text abcdlijkfgd query abcdefg 最大匹配为 abcd 为4 编写一个函数 求字符串可匹配的最大长度 如果是完全匹配 则用很多种方法 如BF KMP sunday等字符串匹配算法 KMP是比较常见的 其思想也
  • 软件项目管理的成功法则

    1 平衡原则 在我们讨论软件项目为什么会失败时可以列出了很多的原因 答案有很多 如管理问题 技术问题 人员问题等等 但是有一个根本的思想问题是最容易忽视的 也是软件系统的用户 软件开发商 销售代理商最不想正视的 那就是 需求 资源 工期 质
  • Jmeter之响应断言

    断言有很多种 最最最常用的一种就是响应断言 目前我也只接触过这么一种 详情 Main sample and sub samples 断言应用于主采样器和子采样器 Main sample only 断言仅应用于主采样器 Sub samples
  • 排序算法的稳定与不稳定

    稳定的排序算法 通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同 在简单形式化一下 如果Ai Aj Ai原来在位置前 排序后Ai还是要在Aj位置前 没错 其实就是有两个排序关键字的时候 稳定排序可
  • 2023华为OD机试真题-数字加减游戏(JAVA、Python、C++)

    题目描述 小明在玩一个数字加减游戏 只使用加法或者减法 将一个数字s变成数字t 每个回合 小明可以用当前的数字加上或减去一个数字 现在有两种数字可以用来加减 分别为 其中b没有使用次数限制 请问小明最少可以用多少次a 才能将数字s变成数字t
  • 我所不知道的TCP Socket编程(五)-交换数据、套接字读写操作

    五 交换数据 已经建立了服务器和客户端的链接 现在需要让它们进行数据交换 你可以将TCP连接想象成一串连接了本地套接字和远程套接字的管子 我们可以沿着这个管子发送和接受数据 实际中 数据被编码为TCP IP分组 经过多台路由器和主机 抵达终