目录
什么是Socket
TCP\IP UDP体系结构
Socket和TCP\IP的关系
Socket在Java中的应用
Socket和SocketChannel的区别
SocketChannel和Selector的关系
服务器的设计演化历程---多线程版
服务器的设计演化历程---线程池版
服务器的设计演化历程---Selector版
参考链接
什么是Socket
理解Socket之间首先需要了解TCP\IP协议:
TCP\IP UDP体系结构
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。下面是他们三者的关系:
在OSI参考模型中将网络分为5层:应用层、传输层、网络层、数据链路层、物理层。
数据在网络中的传输过程:
看上面的图,发送端想要发送数据到接收端。首先
- 应用层准备好要发送的数据,然后给了传输层。
- 传输层的主要作用就是为发送端和接收端提供可靠的连接服务,传输层将数据处理完后就给了网络层。
- 网络层的功能就是管理网络,其中一个核心的功能就是路径的选择(路由),从发送端到接收端有很多条路,网络层就负责管理下一步数据应该到哪个路由器。
- 选择好了路径之后,数据就来到了数据链路层,这一层就是负责将数据从一个路由器送到另一个路由器。
- 然后就是物理层了,可以简单的理解,物理层就是网线一类的最基础的设备。
借助物流的例子理解数据传输过程:
小明住在上海市长江路幸福小区5#666,现在小明在京东上面买了一部小米10Pro。京东在接到小米的订单后,工作人员从仓库中找到一部小米10Pro(应用层)。工作人员将手机打包好, 交给了京东物流(传输层)。接下来手机就到了转运中心(路由器),转运中心根据时间,成本等一系列因素决定下一步该发往哪一个转运中心(网络层)。决定好接下来发往哪一个转运中心后就开始用货车运输了,那么运输的过程就是数据链路层了,链路层负责将数据从一个端点送到另一个端点。那么货车行驶的道路就是物理层。几经周转,手机安全地送到了小明手上。
Socket和TCP\IP的关系
Socket是应用层与TCP\IP协议族通信的中间软件抽象层,它是一组接口。在用户进程与TCP\IP协议之间充当中间人,完成TCP\IP协议的书写,用户只需要理解端口即可。Socket在设计模式中可以理解为一个门面模式,它把复杂的TCP\IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让socket去组织数据,以符合指定的协议。
我们将一个小区比作一台计算机,一台计算机里面跑了很多程序,怎么区分程序呢,用的是端口,就好像小区用门牌号区分每一户人家一样。手机送到小明家了,怎么进去呢?从大门进啊,怎么找到大门呢?门牌号呀。不就相当于从互联网来的数据找到接收端计算机后再根据端口判断应该给哪一个程序一样吗。小明家的入口就可以用小区地址+门牌号进行唯一表示,那么同样的道理,程序也可以用IP+端口号进行唯一标识。那么这个程序的入口就被称作Socket。
Socket在Java中的应用
Socket编程:我们可以参考Java中对Socket的具体实现将TCP协议功能简化为三个功能:建立连接、发送数据以及接收数据。
在Java实现的socket编程中接口实现在以下三个工具包中:
使用Java实现客户端、服务端通信代码如下所示:
// Client
@Slf4j
public class Client {public static void main(String[] args) {try {Socket socket = new Socket("127.0.0.1",9000);ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());oos.writeInt(123);oos.flush();Thread.sleep(3000);Object object = ois.readObject();log.info("client receive messgae : {}", object);} catch (IOException |InterruptedException | ClassNotFoundException e) {e.printStackTrace();}}
}// Server
@Slf4j
public class Server {public static void main(String[] args) {try {ServerSocket serverSocket = new ServerSocket(9000);// serverSocket建立连接后建立的仍然是一个socket对象Socket socket = serverSocket.accept();ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());int serRecvVal = ois.readInt();log.info("serRecvVal : {}", serRecvVal);oos.writeObject("Hello Client.");oos.flush();while (true){}} catch (IOException e) {e.printStackTrace();}}
}
Socket和SocketChannel的区别
Socket、SocketChannel二者的实质都是一样的,都是为了实现客户端与服务器端的连接而存在的,但是在使用上,却有很大的区别。具体如下:
所属包不同
Socket在java.net包中,而SocketChannel在java.nio包中。
异步方式不同
从包的不同,我们大体可以推断出他们主要的区别:Socket是阻塞连接(当然我们可以自己实现非阻塞),SocketChannel可以设置非阻塞连接。
使用ServerSocket、Socket类时,服务端Socket往往要为每一个客户端Socket分配一个线程,而每一个线程都有可能处于长时间的阻塞状态中。过多的线程也会影响服务器的性能(可以使用线程池优化,具体看这里:如何编写多线程Socket程序)。
而使用SocketChannel、ServerSocketChannel类可以非阻塞通信,这样使得服务器端只需要一个线程就能处理所有客户端socket的请求。
SocketChannel和Selector的关系
channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前的 stream 要么是输入,要么是输出,channel 比 stream 更为底层。
常见的channel有:FileChannel、DatagramChannel、SocketChannel、ServerSocketChannle。
Selector可以和网络传输相关的channle结合实现IO多路复用:单线程实现多个channel的connect、read、write时间监听。能够有效避免CPU空转以及阻塞模式带来的影响。
服务器的设计演化历程---多线程版
使用一个Thread监听一个具体的socket,当socket连接数据巨大时,需要开启多个线程来进行监听,内存占用率过高,可能导致OOM。此外多个线程之间需要频繁切换成本高。只适合与连接数比较小的场景使用。
服务器的设计演化历程---线程池版
创建一个线程池,线程池中有若干线程,其中每个线程负责对应的若干socket。
在阻塞模式下,线程只能处理一个socket,并等待其处理结束才能继续处理下一个socket,因此此种模式只适合与但链接的场景下使用。
服务器的设计演化历程---Selector版
selector 的作用就是配合一个线程来管理多个 channel,获取这些 channel 上发生的事件,这些 channel 工作在非阻塞模式下,不会让线程吊死在一个 channel 上。适合连接数特别多,但流量低的场景(low traffic)
调用 selector 的 select() 会阻塞直到 channel 发生了读写就绪事件,这些事件发生,select 方法就会返回这些事件交给 thread 来处理。
参考链接
用大白话解释什么是Socket-CSDN博客
Socket的学习(一)什么是Socket?-CSDN博客
Socket、SocketChannel区别_socketchannel和socket的区别-CSDN博客