Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,其实就是一个门面模式。TCP用主机的IP地址加上主机的端口号,作为TCP连接的端点,这种端点就叫做套接字(Socket)。
长连接和短连接
短连接就是两个主机之间完成一次通信后就断开,比如:UDP和Http1.0。
长连接指两个主机之间完成通信后,不立即断开连接,还可以继续使用进行通信,比如:Http1.1、Http2.0和TCP。
关注的三件事
客户端、服务端和通信编程
总结:
Socket将应用层以下的传输层、网络层和数据链路层都封装起来了,由操作系统提供,应用层只需要通过Socket就可以完成与下层之间的通信。
阻塞IO:Blocking IO (面向流
)
客户端在访问服务器时,当服务器没有响应数据,此时服务端就会创建一个线程,并处于阻塞状态,直至等到服务器数据响应。
存在的问题:
当有很多客户端在请求服务器,而服务器都没有数据响应时,就会创建出很多的线程处于阻塞状态,线程的创建伴随着CPU性能的消耗和内存资源的消耗。
可以通过线程池来避免线程的重复创建和销毁
),负责与客户端的Socket发起连接操作;IO多路复用:No Blocking IO (面向缓冲区
)
为了缓解BIO导致的大量线程创建引起的资源浪费问题,出现了NIO机制,通过服务器创建的一个线程来管理多个客户端发送的请求。
三大核心组件及关系
重要属性
Buffer的分配、读写和常用操作
Buffer是一个抽象类,几乎每一个基本数据类型都有一个实现类,由于网络数据的传递方式是二进制的,所以我们使用到的是ByteBuffer实现类。
Buffer的分配:
可以在堆中分配内存,也可以在直接内存中分配内存。
Buffer的读写操作:
SocketChannel中的read方法其实是往Buffer中写入数据的操作,他的功能是从SocketChannel中读取数据,然后写入Buffer缓冲区中。
SocketChannel中的write方法才是从Buffer缓冲区中读取数据,然后写入到SocketChannel中去
从Buffer中读取数据注意事项:
Buffer在写入数据后,变成从Buffer中读取数据时,就需要先调用flip()
方法,以保证position变成起始位置,limit停留在读取数据的末端;否则,读取数据时候,position还停留在上一次写入数据的那个位置,所以就无法读取到数据。
Buffer的继承关系:
异步IO
因为读取网络数据和写入网络数据,都需要通过系统调用来完成上下文的切换,为了解决这个问题出现了AIO,异步IO.
Windows系统实现了AIO,而Linux是采用的NIO来模拟实现AIO,但是并非是真正实现了AIO。
TCP缓冲区,每个TCP的Socket的操作系统内核中都有一个发送缓冲区(SO_SEDBUF)和一个接收缓冲区(SO_RECVBUFF).
在进行网络通信的过程中,尽可能的申请直接内存。
直接内存相比于堆内存,避免了2次拷贝。因为在堆中申请的内存,需要拷贝到直接内存,然后再拷贝到套接字发送缓冲区中,最终发送给网络;如果在直接内存中申请内存,就直接拷贝到套接字缓冲去中,最终发送给网络。
之所以在堆中申请的内存不能直接跨过直接内存,是因为堆中申请的内存存在GC回收的可能,所以需要拷贝到直接内存中,避免GC回收。
零拷贝(Zero-copy)技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时,节省CPU周期和内存带宽。
零拷贝技术可以减少数据拷贝和共享线程操作的次数,消除传输数据在存储器之间不需要的中间拷贝次数,从而有效的提高数据传输效率。
零拷贝技术减少了用户进程地址空间和内核地址空间之间因为上下文切换而带来的开销。
传统数据传输:
buffer = File.read;
Socket.write(buffer);
第一行代码执行的操作:
首先从内核空间中的磁盘中,通过DMA拷贝将数据拷贝到文件读取缓冲区;然后通过CPU拷贝,将数据拷贝到用户进程的缓存区。
第二行代码执行的操作:
通过CPU拷贝,将数据从用户进程中的缓冲区中拷贝到套接字发送缓冲区(SO_SNDBUF);然后通过DMA拷贝,将套接字发送缓冲区中的数据拷贝到网络设备缓冲区中。
期间总共涉及到4次拷贝和4次上下文切换。
内核缓冲区和网络设备缓冲区都属于内核空间,文件读取缓冲区和套接字发送缓冲区同样属于内核空间;只有应用进程缓冲区才属于用户空间。
3次拷贝,4次上下文切换。
内核空间中的磁盘上的数据通过DMA拷贝到用户进程中的缓冲区,通过MMap内存映射,实现内核空间中的内存数据与应用进程缓冲区的内存数据关联起来;然后再通过CPU拷贝,将用户空间中的应用进程中缓冲区的数据拷贝至套接字缓冲区;最终通过DMA拷贝,将套接字缓冲区中的数据拷贝到网络设备缓冲区中。
内存映射MMap,避免了从磁盘中将数据拷贝至文件缓冲区这个操作,直接将数据从磁盘缓冲区中拷贝到了应用进程缓冲区中;因为经过文件缓冲区,数据是没有做任何更改的,所以为了避免这个操作,直接通过DMA拷贝,从内核空间中的磁盘中将数据拷贝至用户空间中的应用进程中的缓冲区去。
然后磁盘缓冲区和应用进程缓冲区中的数据通过MMap内存映射关联起来,磁盘中的内存中的数据会通过切片,一片内存映射应用进程中内存中的一片内存数据,每一片内存数据都有一个起始地址和结束地址,用于标记这一块内存数据。
3次或2次拷贝,取决于硬件设备是否支持;2次上下文切换。
直接避开用户空间,直接在内核空间中,通过DMA拷贝,从磁盘拷贝数据到文件缓冲区。如果硬件不支持,还需要通过CPU拷贝,将文件缓冲区中的数据拷贝到套接字缓冲区。如果硬件支持,文件缓冲区的数据不需要拷贝至套接字缓冲区,直接将套接字缓冲区中的数据通过DMA拷贝至网络设备缓冲区。
2次拷贝,2次上下文切换
同样是避开用户空间,直接在内核空间中,使得文件缓冲区和套接字发送缓冲区公用同一块内存,之间通过管道通信(PIPE);只需要通过两次DMA拷贝,即可完成数据的传输,通过DMA拷贝将磁盘中数据拷贝到文件缓冲区,由于文件缓冲区与套接字缓冲区是通过管道通信的,所以再通过DMA将套接字缓冲区中的数据拷贝到网络设备缓冲区中。