ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

第8节一文读懂Socket

2021-07-27 12:00:46  阅读:155  来源: 互联网

标签:字节 TCP write 读懂 一文 接字 连接 Socket


1. 前言

最近在研究RDMA的实时流处理系统,其中需要比较RDMA高速网络通信和传统Socket网络通信的传输特点进行比较。所以我们就来总结游戏传统Scoket网络通信的特点,对于一个程序开发人员来说,我们还需要了解Scoket网络通信的底层数据传输知识。

2. Socket简介

Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。

应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

2.1 Socket 连接过程

根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。

(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。

(2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

在这里插入图片描述

使用Scoket面向连接的通信过程:

在这里插入图片描述

3. 深入理解Scoket网络数据通信

socket字面意思其实就是一个插口或者套接字,包含了源ip地址、源端口、目的ip地址和源端口。我们都学过TCP/IP五层网络协议和OSI七层网络协议,那么Socket是在这些网络协议中的哪个位置呢?
在这里插入图片描述

通过上面这幅图,我们发现Scoket位于TCP/IP五层网络协议中运输层和应用层之间抽象的一组Socket抽象层,它是一组网络传输接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。一般由操作系统或者JVM自己实现。Java和.NET中的socket其实就是对底层的抽象调用。有一点需要注意,运行在同一主机上的其他应用程序可能也会通过底层套接字抽象来使用网络,因此会与java socket实例竞争资源,如端口。

对于“套接字结构”,是指底层实现(包括JVM和TCP/IP,但通常是后者)的数据结构集,包含了特定Socket所关联的信息。套接字和套接字数据结构是不一样的概念。

3.1 套接字结构

Socket套接字结构包含:

  • 该套接字所关联的本地和远程互联网地址和端口。
  • 一个FIFO队列用于存放接收到的等待分配的数据(RecvQ),以及一个用于存放等待传输数据的的队列(SendQ)。他们都是用来存放数据缓存的数据结构。可以通过Socket的InputStream和OutputStream从中获取数据流。
  • 对于TCP套接字,还包含了与打开关闭TCP握手相关的额外协议状态信息。

在这里插入图片描述

  • 一些多用户操作系统提供获得底层数据结构快照的工具,netstat可以查看本地和远程IP地址和端口的连接状态和sendQ和RecvQ中的字节数。

**TCP是一种可信赖的字节流服务,任何写入socket输出流的数据副本必须保留(保留到本地缓冲区),直到另一端成功的接收。**向输出流写数据并不意味着数据实际上已经被发送——它们只是被复制到了本地缓冲区,就算在Socket的OutputStream上进行flush()操作,也不能保证数据能够立即发送到信道。此外,字节流服务的自身属性决定了其无法保留输入流中消息的边界信息。

3.2 数据传输的底层实现

一般来讲,我们可以认为TCP连接上发送的所有字节序列在某一瞬间被分成了3个FIFO队列:

  • SendQ:在发送端底层实现中缓存的字节,这些字节已经写入输出流,但还没在接收端成功接收。它占用大约37KB内存。
  • RecvQ:在接收端底层实现中缓存的字节,这些字节等待分配到接收程序——即从输入流中读取。它占用大约25KB内存。
  • Delivered:接收者从输入流已经读取到的字节。

这三个FIFO队列就相当于TCP中的发送缓存和接受缓存以及已经交付的缓存。

  • 1.当我们调用OutputStream的write()方法时,将向SendQ追加字节。
  • 2.TCP协议负责将字节按顺序从SendQ移动到RecvQ。这里有重要的一点需要明确:这个转移过程无法由用户程序控制或直接观察到,并且在网络层中发生,这些IP数据包的大小在一定程度上独立于传递给write()方法的缓冲区大小。
  • 3.接收程序从Socket的InputStream读取数据时,字节就从RecvQ移动到Delivered中,而转移的IP数据包的大小依赖于RecvQ中的数据量和传递给read()方法的缓冲区的大小。

3.3 缓存和数据传输

Socket输入数据流和输出数据流之间没有任何一致性的联系。能假设从一端写入输出流的数据和在另一端从输入流读出数据之间有任何的一致性。尤其是在发送端由单个输出流的write()方法传输数据,可能要经过另一端的多个read()方法获取,而一个read()方法可以返回多个write()写入的内容。为了展示这种情况,给出如下程序:

在这里插入图片描述

对于上面这个例子,我们只需要进行如下操作就能读取所有write的数据:

public int read(byte b[]) throws IOException

其中,圆点代表了设置缓冲区数据的代码,但不包含对out.write()方法的调用。这个TCP连接向接收端传输8000字节,在连接的接收端,这8000字节的分组方式取决于连接两端的out.write()方法和in.read()方法的调用时间差,以及提供给in.read()方法的缓冲区的大小。

下图展示了3次调用out.write()方法后,另一端调用in.read()方法前,以上3个队列的一种可能状态。不同的阴影效果分别代表了上文中3次调用write()方法传输的不同数据:

在这里插入图片描述

现在假设接收者调用read()方法时使用的缓冲区数组大小为2000字节,read()调用则将把RecvQ中的1500字节全部移动到数组中,返回值为1500。注意,这些数据中包含了第一次和第二次调用write()方法时传输的字节,再过一段时间,当TCP连接传完更多数据后,这三部分的状态可能如下图所示:

在这里插入图片描述

如果接收者现在调用read()方法时使用4000字节的缓冲区数组,将有很多字节从RecvQ队列转移到Delivered队列中,这包括第二次调用write()方法时剩下的1500字节加上第三次调用write()方法的钱2500字节。此时,队列的状态如下图:

在这里插入图片描述

4. 从TCP网络传输协议分析Socket通信数据传输

TCP网络传输是面向字节流:TCP中的流(Stream)就是指的是流入到进程或者从进程流出的字节序列。虽然应用程序和TCP的交互是一次一个数据块(也就是我们定义的不同大小的Buffer长度),但是TCP把应用程序交互下来的数据仅仅是看成是一连串的无结构的字节流,并且将这一连串应用程序交互下来的数据放入TCP中的发送缓存中。

在这里插入图片描述

如图所示,应用程序可能交付给发送方100个数据块大小,但是实际上数据传输可能是10个数据块封装成一个报文段进行数据传输,接受方的TCP可能只用了20个数据块就把收到的字节流交付给上层应用程序了。

TCP并不关心应用程序一次把多长的报文发送到TPC的缓存中去,而是根据对方给出的窗口值的大小和当前网络拥塞程度来决定一个报文段应该包含多少个字节。如果应用进程传输到TCP缓存的数据块太长,TCP就可以把它划分短一些再进行数据传输,TCP也可以积累足够长的数据之后再进行网络传输。

在这里插入图片描述

TCP的传输效率

TCP的发送方有发送缓冲区,应用程序将要发送的数据交给TCP的发送缓冲区就不管了。那么TCP应该何时将数据发送出去呢?有3种机制:

  • TCP维持一个最大报文长度MSS的变量,当缓冲区中存放的数据达到MSS字节时,就组装成一个TCP报文段发送出去。
  • 由发送方的应用进程指明要求发送报文段,即TCP支持的推送(PUSH)操作
  • 发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(长度不能超过MSS)发送出去。

标签:字节,TCP,write,读懂,一文,接字,连接,Socket
来源: https://blog.csdn.net/pjh88/article/details/119139900

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有