揭秘socket
什么是socket?socket字面意思其实就是一个插口或者套接字,包含了源ip地址、源端口、目的ip地址和源端口。但是socket在那个位置呢
在TCP/IP网络的四层体系和OSI七层好像都找不到他的影子,那么下面看一张图就可以明白了。
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。一般由操作系统或者JVM自己实现。java.net中的socket其实就是对底层的抽象调用。有一点需要注意,运行在同一主机上的其他应用程序可能也会通过底层套接字抽象来使用网络,因此会与java socket实例竞争资源,如端口。对于“套接字结构”,是指底层实现(包括JVM和TCP/IP,但通常是后者)的数据结构集,包含了特定Socket所关联的信息。套接字和套接字数据结构是不一样的概念。套接字结构包含:
1.该套接字所关联的本地和远程互联网地址和端口。
2.一个FIFO队列用于存放接收到的等待分配的数据(RecvQ),
以及一个用于存放等待传输数据的的队列(SendQ)。
3.对于TCP套将诶子,还包含了与打开关闭TCP握手相关的额外协议状态信息。
一些多用操作系统提供获得底层数据结构快照的工具,netstat可以查看本地和远程IP地址和端口的连接状态和sendQ和RecvQ中的字节数。
TCP是一种可信赖的字节流服务,任何写入socket输出流的数据副本必须保留(保留到本地缓冲区),直到另一端成功的接收。向输出流写入信息并不意味着数据实际上已经被发送,他们只是被复制到了本地缓冲区。就算调用flush()也不会保证能立即发送到信道。
缓冲与数据传输
!!!不能假设从一端写入输出流的数据和在另一端从输入流读出数据之间有任何的一致性。
尤其是在发送端由单个输出流的write()方法传输数据,可能要经过另一端的多个read()方法获取,而一个read()方法可以返回多个write()写入的内容。
为了展示这种情况,给出如下程序:
这个TCP连接向接收端传输8000字节,在接收端这些字节的分组方式,取决于read和write调用的时间差,以及提供给in.read的缓冲区大小。
我们可以认为TCP连接上发送的字节序列在某一个瞬间分成了3个FIFO序列。
1.sendQ:在发送端底层实现中缓存的字节,这些字节已经写入网络流,还没有被接收端收到。
2.RecvQ:在接收端底层实现中缓存的字节,等待分配到应用程序——即从输入流中读取数据。
3.Delivered:接收着从输入流中已经读取到的字节。
sendQ中的字节既然存在就表明 对方还没有收到,是为了防止网络异常重发。out.write()是向sendQ追加字节。
然后又sendQ向RecvQ发送的过程不能由用户程序看到和观察,并且以块(chunk)的形式传输,chunk的大小与write()写入的字节大小无关。
从RecvQ读取数据时,字节从RecvQ发送到delivered中 ,转移的chunk的大小与RecVQ中的字节和read(BUF)中缓冲区的大小有关。
下面是截取的三个状态的三个缓冲区的大小。
总结:Socket实际上就是对Tcp接口的封装,使用socket可以直接操作TCP协议栈,要想在了解是怎么封装的,我想只有看一下源码才能知道他是怎么实现的。