-
socket
-
Socket
-
--> 数据包经由应用程序产生
-
--> 通过协议栈进行报文头包装
-
--> 操作系统调用网卡驱动程序指挥硬件,将数据发送到对端主机 Socket在这个流程中提供了应用程序与网络层之间的接口
-
TCP Socket 面向连接的可靠传输
-
Socket 类和 ServerSocket 类
-
通过输入输出流(InputStream和OutputStream)来发送和接收字节流。这些字节流在底层被封装成数据包,由操作系统和网络协议栈处理
-
-
UDP Socket 面向无连接的高效传输
-
DatagramSocket 和 DatagramPacket 两个主要类
-
DatagramPacket类表示一个UDP数据包,包含了一个字节数组以及该数组的长度,还有源和目标的IP地址和端口号。通过DatagramSocket来发送和接收DatagramPacket,从而在网络上进行UDP通信。
-
-
-
TCP Socket
-
服务器端
-
创建ServerSocket对象,指定端口号监听连接请求
-
ServerSocket serverSocket = new ServerSocket(portNumber);
-
-
阻塞住,等待连接
-
Socket clientSocket = serverSocket.accept();
-
-
获取 输入流(如InputStream或BufferedReader) 输出流(如OutputStream或PrintWriter),与客户端通信
-
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
-
-
读写数据
-
读取客户端发送数据
-
String inputLine = in.readLine();
-
-
向客户端发送数据
-
out.println("......");
-
-
-
关闭连接
-
clientSocket.close(); serverSocket.close();
-
-
-
客户端
-
创建Socket对象
-
Socket socket = new Socket(serverIP, portNumber);
-
-
通过socket对象获取输入输出流
-
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
-
-
读写数据
-
发送给服务端
-
out.println("......");
-
-
读取服务器返回数据
-
String response = in.readLine();
-
-
-
关闭连接
-
socket.close();
-
-
-
-
UDP Socket
-
服务器端
-
创建DatagramSocket对象 接收客户端发送数据报
-
DatagramSocket serverSocket = new DatagramSocket(portNumber);
-
-
接收数据报
-
byte[] buffer = new byte[bufferSize]; DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length); serverSocket.receive(receivePacket);
-
-
处理接收到的数据
-
String receivedData = new String(receivePacket.getData(), 0, receivePacket.getLength()); InetAddress senderIP = receivePacket.getAddress(); int senderPort = receivePacket.getPort();
-
-
发送响应(非必要)
-
String responseData = "Received yourmsg";
-
byte[] sendData = responseData.getBytes();
-
InetAddress clientIP = receivePacket.getAddress(); // 通常使用客户端的IP地址作为目标地址 int clientPort = receivePacket.getPort(); // 通常使用客户端的端口号作为目标端口
-
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, clientIP, clientPort); serverSocket.send(sendPacket);
-
-
关闭连接 关闭DatagramSocket对象
-
serverSocket.close();
-
-
-
客户端
-
创建DatagramSocket对象
-
DatagramSocket clientSocket = new DatagramSocket();
-
-
准备发送数据
-
String sendData = "msg from client!";
-
byte[] sendBuffer = sendData.getBytes();
-
InetAddress serverIP = InetAddress.getByName("serverIPAddress");
-
int serverPort = portNumber;
-
-
发送数据报
-
DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, serverIP, serverPort);
-
clientSocket.send(sendPacket);
-
-
接收响应(非必要)
-
关闭连接
-
clientSocket.close();
-
-
-
-
消息推送方式
-
轮询
-
客户端按照固定的时间间隔(例如,每几秒或几分钟)向服务器发送请求,以检查是否有新的消息或更新。服务器响应这些请求,返回客户端所需的数据。
-
-
长轮询
-
客户端向服务器发送一个请求,然后服务器会保持这个连接打开,直到有新数据可用或者达到某个超时时间。当服务器有新数据时,它会立即将数据返回给客户端并关闭连接。如果达到超时时间但还没有新数据,服务器会发送一个空响应或特定的超时消息,然后关闭连接。客户端在收到响应后,会立即重新发起一个新的长轮询请求,以等待下一个数据更新。
-
-
SSE
-
是一种服务器向客户端推送实时更新的简单方式,它基于HTTP协议,但实现了类似WebSocket的服务器推送功能。SSE使用一种简单的文本/事件流格式来发送事件,允许服务器向客户端推送更新。
-
-
websocket
-
是一种在单个TCP连接上进行全双工通信的协议。它被设计用来解决传统HTTP协议中客户端向服务器发送请求、服务器响应后连接关闭的问题,从而实现了服务器可以主动向客户端推送数据的功能
-
-
-
socket.io
-
用于实时双向通信的 JavaScript 库
-
Socket.IO 由两部分组成:
-
Socket.IO 客户端库:在浏览器或其他客户端环境中运行,用于与服务器进行实时通信。
-
Socket.IO 服务器库:在 Node.js 或其他后端环境中运行,用于处理来自客户端的连接和消息。
-
-
WebSocket
-
服务端
-
方法
-
onOpen()
-
onClose()
-
onError()
-
-
-
-
注解
-
@OnOpen
-
@OnClose
-
@OnError
-
-
-
-
服务端接收数据
-
MessageHandler
-
@OnMessage
-
-
服务端推送数据
-
Session对象
-
同步、异步
-
-
-
-
客户端
-
对象创建
-
let ws = new WebSocket(URL:'ws://localhost/chat');
-
-
对象相关事件
-
事件
-
事件处理程序
-
描述
-
-
-
open
-
ws.onopen
-
连接建立时触发
-
-
-
message
-
ws.onmessage
-
客户端接收到服务器发送的数据时触发
-
-
-
close
-
ws.onclose
-
连接关闭时触发
-
-
-
-
对象提供的方法
-
send();
-
通过webSocket对象调用该方法发送数据给服务端
-
-
-
自由主题
-
-
-
-
协议设计与解析
-
Redis
-
*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n
-
-
HTTP
-
Netty提供解码器
-
HttpRequestDecoder:将字节流解码为 HTTP 请求 HttpResponseEncoder:将 HTTP 响应编码为字节流 HttpObjectAggregator:将多个 HTTP 消息对象(例如 HTTP 请求头和内容)聚合成一个完整的 HTTP 消息
-
SimpleChannelInboundHandler<HttpRequest>()
-
代码示例
@Override public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { // 1. 4 字节的魔数 out.writeBytes(new byte[]{1, 2, 3, 4}); // 2. 1 字节的版本, out.writeByte(1); // 3. 1 字节的序列化方式 jdk 0 , json 1 out.writeByte(0); // 4. 1 字节的指令类型 out.writeByte(msg.getMessageType()); // 5. 4 个字节 out.writeInt(msg.getSequenceId()); // 无意义,对齐填充,凑偶数字节 out.writeByte(0xff); // 6. 获取内容的字节数组 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(msg); byte[] bytes = bos.toByteArray(); // 7. 长度 out.writeInt(bytes.length); // 8. 写入内容 out.writeBytes(bytes); }
-
-
-
自定义协议
-
自定义
-
--魔数,用来在第一时间判定是否是无效数据包
-
--版本号,可以支持协议的升级
-
--序列化算法,消息正文到底采用哪种序列化反序列化方式,可以由此扩展,例如:json、protobuf、hessian、jdk
-
--指令类型,是登录、注册、单聊、群聊..跟业务相关
-
--请求序号,为了双工通信,提供异步能力
-
--正文长度
-
--消息正文
-
-
自定义协议代码示例
-
编码
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { int magicNum = in.readInt(); byte version = in.readByte(); byte serializerType = in.readByte(); byte messageType = in.readByte(); int sequenceId = in.readInt(); in.readByte(); int length = in.readInt(); byte[] bytes = new byte[length]; in.readBytes(bytes, 0, length); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); Message message = (Message) ois.readObject(); log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length); log.debug("{}", message); out.add(message); }
-
解码(编码逆过程)
-
-
-
-
TCP/UDP Socket、消息推送、自定义编码解码器(协议)
于 2024-06-04 15:05:32 首次发布