我所不知道的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编程(五)-交换数据、套接字读写操作 的相关文章

  • 为什么turn服务器不支持tcp连接?

    我是 WebRTC 新手 我需要为我的 webrtc 应用程序配置我自己的 Turn 服务器 我使用以下命令安装了我的转弯服务器 apt get install coturn 我只需要通过 tcp 运行转变服务器 它不必使用 UDP 进行任
  • 自动打开命名管道和 tcp\ip

    我正在安装一个需要修改 SQL Server 的新产品 具体来说 启用 tcp ip 并打开命名管道 我知道如何手动完成 我想要的是一种通过 SQL 或 C 代码为新客户自动化执行此操作的方法 我希望有任何关于正确方向的建议 您可以使用 C
  • 简单的跨平台 TCP IP API?

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

    我正在尝试访问 AWS 上的 Tensorboard 这是我的设置 张量板 tensorboard host 0 0 0 0 logdir train 在端口 6006 上启动 TensorBoard b 39 您可以导航到http 172
  • iOS 上的多个 HTTP 请求与单个 TCP 连接

    我正在开发一个 iPhone 应用程序 它使用我控制的基于 Web 的 API 连接到持续打开的 TCP 端口并通过 TCP API 发出请求 或者为我想要获取的所有数据发出新的 HTTP 请求 会更快或更高效吗 我认为差异可以忽略不计 但
  • 分配 TCP/IP 端口供内部应用程序使用

    我编写了一个由 Windows 服务托管的 WCF 服务 它需要侦听已知的 TCP IP 端口 我可以在什么范围内安全地分配端口供我的组织内使用 该端口将嵌入到服务和使用该服务的客户端的配置文件中 端口 0 1023 是众所周知的端口 由
  • 如果其中一台机器死机,TCP 连接如何终止?

    如果两个主机 A 和 B 之间建立了 TCP 连接 假设主机 A 已向主机 B 发送了 5 个八位字节 然后主机 B 崩溃了 由于未知原因 主机 A 将等待确认 但如果没有收到确认 将重新发送八位字节并减小发送者窗口大小 这将重复几次 直到
  • 如何在Linux内核源代码中打印IP地址或MAC地址

    我必须通过修改 Linux 内核源代码来稍微改变 TCP 拥塞控制算法 但为了检查结果是否正确 我需要记录 MAC 或 IP 地址信息 我使用 PRINTK 函数来打印内核消息 但我感觉很难打印出主机的MAC IP地址 printk pM
  • 如何抑制Windows防火墙的Windows安全警报?

    当我从这里找到的 ZeroMQ 指南中用 C 创建 Hello World 示例时 http zguide zeromq org page all Ask and Ye Shall Receive http zguide zeromq or
  • 如何知道哪个本地应用程序连接到我的套接字(Windows)

    我有一个绑定到某个 TCP 端口的 Windows 服务 该端口用于我的应用程序之间的 IPC 有没有一种编程 WinAPI WinSocket 等 方法可以知道哪个应用程序连接到我的端口 即在我的 Windows 服务中 我想获取连接到我
  • 了解 netty 通道缓冲区和水印

    我正在尝试了解网络缓冲区和水印 作为一个测试用例 我有一个 netty 服务器 它向客户端写入数据 客户端被阻止 基本上每次读取之间有 10 秒的睡眠时间 在正常 I O 下 如果接收方被阻塞 TCP 发送方将受到限制 由于流量控制 发送速
  • 使用 IdTCPClient 和 IdTCPServer 发送和接收 TMemoryStream

    我在 XE2 中找到了 Remy Lebeau 的 IdTCP 组件聊天演示 我想玩一下 可以发现 我想使用这些组件发送图片 最好的方法似乎是使用 TMemoryStream 如果我发送字符串 连接工作正常 字符串传输成功 但是当我将其更改
  • 立即检测客户端与服务器套接字的断开连接

    如何检测客户端已与服务器断开连接 我的代码中有以下代码AcceptCallBack method static Socket handler null public static void AcceptCallback IAsyncResu
  • TCP 连接寿命

    客户端 服务器 TCP 连接在野外可以持续多长时间 我希望它保持永久连接 但事情发生了 所以客户端将不得不重新连接 我什么时候可以说代码有问题而不是某些外部设备有问题 我同意赞 林克斯的观点 虽然无法保证 但假设不存在连接或带宽问题 您可以
  • Docker 容器是否有自己的 TCP/IP 堆栈?

    我试图了解来自连接到主机的线路并定向到 Docker 容器内的应用程序的网络数据包在幕后发生了什么 如果它是一个经典的 VM 我知道到达主机的数据包将由虚拟机管理程序 例如 VMware VBox 等 传输到 VM 的虚拟 NIC 并从那里
  • Silverlight 套接字:模仿框架 Bind、Listen 和 Accept 方法?

    我有这个 NET Framework C 类 它实际上充当 TCP 连接的包装器Socket http msdn microsoft com en us library attbb8f5 aspxSystem Net Sockets 命名空
  • PHP 通过 TCP/IP 发送消息

    我尝试通过 TCP IP 从 PHP 网站向 Arduino 发送消息 使用以下代码我可以从 php 网站发送消息 问题是 当第一次调用该网站时 消息不会立即发送 网站刷新几次后 消息就会到达 但逻辑上很多次 就像网站刷新量一样 已经尝试将
  • 10G 链路的 netcat 和 iperf 结果存在巨大差异

    我很困惑看到 netcat 和 iperf 结果之间的巨大差异 我有 10 G 链路连接我的服务器和客户端 iperf 的速度约为 10Gb s 但 netcat 的速度仅为约 280 MB s 可能是什么错误 对于 Iperf Serve
  • C# P2P聊天应用程序设计

    我想创建一个不使用显式服务器的简单聊天应用程序 主要要求是用户可以同时与许多朋友聊天 就像在 Skype 等上一样 我在这里指的不是会议聊天 而是多个单独的聊天窗口 目前 我只想要一个 LAN 消息应用程序 但如果设计能够轻松扩展到 Int
  • 伪TCP通道

    什么是伪 TCP 通道以及如何实现 伪 TCP 是一种协议 它实现了 TCP 的一些思想 通过不可靠的基于数据包的接口提供可靠的数据流 例如 如果您只能访问 UDP 但想要 一种可靠的方式来传递数据 则可以使用此方法 您可以在这里找到示例代

随机推荐

  • 网页在线视频下载教程(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分组 经过多台路由器和主机 抵达终