websocket和socket的关系和区别
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员
做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,
提供了网络通信的能力。
连接过程:
(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
(2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
HTTP协议是非持久化的,单向的网络协议,在建立连接后只允许浏览器向服务器发出请求后,服务器才能返回相应的数据。
当需要即时通讯时,通过轮询在特定的时间间隔(如1秒),由浏览器向服务器发送Request请求,然后将最新的数据返回给浏览器。这样的方法最明显的缺点就是需要不断的发送请求,而且通常HTTP request的Header是非常长的,为了传输一个很小的数据 需要付出巨大的代价,是很不合算的,占用了很多的宽带。会导致过多不必要的请求,浪费流量和服务器资源,每一次请求、应答,都浪费了一定流量在相同的头部信息上
WebSocket的出现可以弥补这一缺点。在WebSocket中,只需要服务器和浏览器通过HTTP协议进行一个握手的动作,然后单独建立一条TCP的通信通道进行数据的传送。
1、WebSocket同HTTP一样也是应用层的协议,但是它是一种双向通信协议,是建立在TCP之上的。
2、WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。
3、WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。
使用websocket完成后台给web端推送消息:
pom依赖,使用的版本是4.1.4.RELEASE
<!-- WebSocket -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${webSocket.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${webSocket.version}</version>
</dependency>
处理消息的MyMessageHandler
package com.yofc.cloud.websocket;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.*;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class MyMessageHandler implements WebSocketHandler {
private static final Logger log = Logger.getLogger(MyMessageHandler.class);
public static final String SESSION_KEY = "current_session";
private final static Map<String, WebSocketSession> sessionMap;
static {
sessionMap = new ConcurrentHashMap<String, WebSocketSession>(30);
}
@Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
sessionMap.put(SESSION_KEY, webSocketSession);
log.info("websocket connection success");
// webSocketSession.sendMessage(new TextMessage("websocket connection success"));
}
@Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
String msg = webSocketMessage.toString();
log.info("服务端已经接收到消息,msg=" + msg);
webSocketMessage = new TextMessage("服务端已经接收到消息,msg=" + msg);
webSocketSession.sendMessage(webSocketMessage);
}
@Override
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
log.info("websocket链接出现异常");
WebSocketMessage<String> message = new TextMessage("异常信息:" + throwable.getMessage());
webSocketSession.sendMessage(message);
}
/**
* 关闭websocket时调用该方法
*
* @param webSocketSession
* @param closeStatus
* @throws Exception
*/
@Override
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
log.info("websocket connection close");
}
@Override
public boolean supportsPartialMessages() {
return false;
}
public void sendMsgToUser(String contents) {
WebSocketSession session = sessionMap.get(SESSION_KEY);
if (session != null && session.isOpen()) {
try {
TextMessage message = new TextMessage(contents);
session.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
配置websocket链接地址 WebSocketConfig
package com.yofc.cloud.websocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
/**
* register handler
* @param webSocketHandlerRegistry
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(myHandler(),"cloudDiskHandler").addInterceptors(new WebSocketInterceptor());
webSocketHandlerRegistry.addHandler(myHandler(), "/socketJs/cloudDiskHandler").addInterceptors(new WebSocketInterceptor()).withSockJS();
}
@Bean
public WebSocketHandler myHandler(){
return new MyMessageHandler();
}
}
websocket适配器
package com.yofc.cloud.websocket;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import java.util.Map;
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
/* if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
//获取参数
String userId = serverHttpRequest.getServletRequest().getParameter("userId");
attributes.put(MyMessageHandler.USER_KEY, userId);
}*/
return true;
}
}
调用方法给前段发送消息
//注入
@Autowired
private MyMessageHandler handler;
//这个方法现在任何位置都可以给web端发送消息
handler.sendMsgToUser(answerMessage.toString());
web端代码 页面创建时执行此方法
websocketListener() {
console.log(window.location.host);
var websocket;
var url = window.location.host;
//var url = "localhost:8080";
let self = this;
// 首先判断是否 支持 WebSocket
if ("WebSocket" in window) {
// websocket = new WebSocket("ws://localhost:8080/cloudDiskHandler");
websocket = new WebSocket("ws://" + url + "/cloudDiskHandler");
} else if ("MozWebSocket" in window) {
websocket = new MozWebSocket("ws://" + url + "/cloudDiskHandler");
} else {
websocket = new SockJS("http://" + url + "/socketJs/cloudDiskHandler");
}
// 打开连接时
websocket.onopen = function(evnt) {
console.log(" websocket.onopen ");
};
// 收到消息时
websocket.onmessage = function(evnt) {
console.log(evnt.data);
self.$message({
showClose: true,
message: evnt.data
});
};
websocket.onerror = function(evnt) {
console.log(" websocket.onerror ");
};
websocket.onclose = function(evnt) {
console.log(" websocket.onclose ");
};
function say() {
//客户端主动发消息
// websocket.send("client socket success");
}
},