程序猿成长之路之socket篇-socket通信原理简介
hello,各位小伙伴们大家好,上次以RSA加解密算法介绍作为密码学篇的结尾后,时光飞逝,转眼到了新一年的春季,这次将介绍一下socket通信和编程原理。
什么是socket(套接字)?
socket(套接字)是网络传输的一种工具,它是介于应用层与传输层之间,了解过七层OSI协议的同学应该知道,socket是基于TCP/IP协议进行网络传输的。socket分为server端和client端,它支持全双工式网络通信。
socket(套接字)有哪些用途?
说起socket的用途,大家可能首先会联想到聊天室,没错,这个就是socket的一类应用。由于全双工式的通信,socket可以支持双向的信息发送与接收。此外,socket还可以编写服务端向客户端主动发送消息。总之,有了socket,网络通信就变得容易了。
socket(套接字)其他知识
socket 生命周期
什么是websocket?
WebSocket是一种在单个TCP连接上进行全双工通信的协议。它允许客户端和服务器之间进行简单而有效的双向数据传输。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。这个握手过程是通过HTTP/1.1协议的101状态码进行的。
websocket实现方式
websocket client端
const host = 'localhost'//设置自己的socket host
const port = 8888 //设置自己的socket port
const ws = new WebSocket(`ws://${host}:${port}/websocket/${username}`)
ws.onopen = () => {
//创建完成websocket
console.log('client opened')
}
ws.onmessage = (msg) => {
//接收到消息
console.log(msg);
}
ws.onerror = (err) => {
//出错
console.log(err);
}
ws.onclose = () => {
//websocket关闭时执行
console.log("client closed")
}
websocket server端(node.js版)
onst ws = require('ws');
const wss = new ws.Server({port:8888});
wss.on('connection',function onConnection(ws) {
ws.on('open',function onOpen(){
console.log('connected!');
ws.send("hello");
});
ws.on('message',function onMessage(msg){
//批量群发
wss.clients.forEach(function each(client) {
//如果socket 为连接状态就发送消息
if (client.readyState === ws.OPEN) {
client.send(msg);
}
})
})
ws.on('close',function onOpen(){
console.log('closed!');
});
})
websocket server端(java版)
配置类:
/**
* WebSocket配置类。开启WebSocket的支持
*/
@Configuration
public class WebSocketConfig {
/**
* bean注册:会自动扫描带有@ServerEndpoint注解声明的Websocket Endpoint(端点),注册成为Websocket bean。
* 要注意,如果项目使用外置的servlet容器,而不是直接使用springboot内置容器的话,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
websocket 消息 实体类
/**
* 消息实体类
* @author zygswo
*/
@Data
@Accessors(chain = true)
@NoArgsConstructor
@ToString
public class Message implements Serializable {
/**
* 来源
*/
private String from;
/**
* 目标
*/
private String to;
/**
* 正文
*/
private String message;
/**
* 发送时间
*/
private String date;
/**
* 是否系统消息
*/
private boolean sysmsg;
}
websocket实现类:
package com.myhouse.common.utils.myWebsocket;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* ServerEndpoint注解表示开启websocket并且参数表示websocketserver 路径
*/
@Component
@Slf4j
@Getter
@ServerEndpoint("/websocket/{username}")
public class MyWebSocket {
/**
* 在线人数
*/
private static AtomicInteger totalNb = new AtomicInteger(0);
/**
* websocket列表
*/
private static Map<String,MyWebSocket> socketMap = new ConcurrentHashMap<>();
/**
* 在线人数
*/
private Session session;
/**
* 用户名
*/
private String username;
/**
* 开启服务
* @param username 用户名称
* @param session session
*/
@OnOpen
public void onOpen(@PathParam("username") String username, Session session) {
this.username = username;
this.session = session; //保存当前会话
addOnlineCount(); //在线数加1
log.info("欢迎用户" + username + " 加入聊天室!当前在线人数为: " + getOnlineCount());
}
/**
* 获取到消息后
* @param message 消息
*/
@OnMessage
public void onMessage(String message) {
Message msg = JSON.parseObject(message, Message.class);
try {
if (msg.getTo().equalsIgnoreCase("all")) {
for (MyWebSocket socket : socketMap.values()) {
socket.sendMessage(message);
}
} else {
socketMap.get(msg.getTo()).sendMessage(message);
}
}catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发送消息
* @param message 消息
*/
private void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 获取到消息后
* @param session session
* @param err 错误消息
*/
@OnError
public void onError(Session session, Throwable err) {
System.out.println("发生错误");
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
log.error(err.getMessage());
err.printStackTrace();
}
/**
* socket连接关闭
*/
@OnClose
public void onClose() {
log.info(this.username + "退出聊天室!当前在线人数为" + getOnlineCount());
socket.sendMessage(msg);
socketMap.remove(this.username);
}
/**
* 新增在线人数
*/
private static void addOnlineCount() {
totalNb.incrementAndGet();
}
/**
* 减少在线人数
*/
private static void substractOnlineCount() {
totalNb.decrementAndGet();
}
/**
* 获取在线人数
* @return 在线人数
*/
public static int getOnlineCount() {
return totalNb.get();
}
}