0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

WebSocket的6種集成方式介紹

jf_ro2CN3Fa ? 來源:CSDN ? 2023-09-02 16:52 ? 次閱讀

介紹

由于前段時(shí)間我實(shí)現(xiàn)了一個(gè)庫【Spring Cloud】一個(gè)配置注解實(shí)現(xiàn) WebSocket 集群方案

以至于我對(duì)WebSocket的各種集成方式做了一些研究

目前我所了解到的就是下面這些了(就一個(gè)破ws都有這么多花里胡哨的集成方式了?)

Javax

WebMVC

WebFlux

Java-WebSocket

SocketIO

Netty

今天主要介紹一下前3種方式,畢竟現(xiàn)在的主流框架還是Spring Boot

而后3種其實(shí)和Spring Boot并不強(qiáng)行綁定,基于Java就可以支持,不過我也會(huì)對(duì)后3種做個(gè)簡(jiǎn)單的介紹,大家先混個(gè)眼熟就行了

那么接下來我們就來講講前3種方式(Javax,WebMVC,WebFlux)在Spring Boot中的服務(wù)端和客戶端配置(客戶端配置也超重要的有木有,平時(shí)用不到,用到了卻基本找不到文檔,這也太絕望了)

Javax

在java的擴(kuò)展包javax.websocket中就定義了一套WebSocket的接口規(guī)范

服務(wù)端

一般使用注解的方式來進(jìn)行配置

第一步

@Component
@ServerEndpoint("/websocket/{type}")
publicclassJavaxWebSocketServerEndpoint{

@OnOpen
publicvoidonOpen(Sessionsession,EndpointConfigconfig,
@PathParam(value="type")Stringtype){
//連接建立
}

@OnClose
publicvoidonClose(Sessionsession,CloseReasonreason){
//連接關(guān)閉
}

@OnMessage
publicvoidonMessage(Sessionsession,Stringmessage){
//接收文本信息
}

@OnMessage
publicvoidonMessage(Sessionsession,PongMessagemessage){
//接收pong信息
}

@OnMessage
publicvoidonMessage(Sessionsession,ByteBuffermessage){
//接收二進(jìn)制信息,也可以用byte[]接收
}

@OnError
publicvoidonError(Sessionsession,Throwablee){
//異常處理
}
}

我們?cè)陬惿咸砑覢ServerEndpoint注解來表示這是一個(gè)服務(wù)端點(diǎn),同時(shí)可以在注解中配置路徑,這個(gè)路徑可以配置成動(dòng)態(tài)的,使用{}包起來就可以了

@OnOpen用來標(biāo)記對(duì)應(yīng)的方法作為客戶端連接上來之后的回調(diào),Session就相當(dāng)于和客戶端的連接啦,我們可以把它緩存起來用于發(fā)送消息;通過@PathParam注解就可以獲得動(dòng)態(tài)路徑中對(duì)應(yīng)值了

@OnClose用來標(biāo)記對(duì)應(yīng)的方法作為客戶端斷開連接之后的回調(diào),我們可以在這個(gè)方法中移除對(duì)應(yīng)Session的緩存,同時(shí)可以接受一個(gè)CloseReason的參數(shù)用于獲取關(guān)閉原因

@OnMessage用來標(biāo)記對(duì)應(yīng)的方法作為接收到消息之后的回調(diào),我們可以接受文本消息,二進(jìn)制消息和pong消息

@OnError用來標(biāo)記對(duì)應(yīng)的方法作為拋出異常之后的回調(diào),可以獲得對(duì)應(yīng)的Session和異常對(duì)象

第二步

implementation'org.springframework.boot:spring-boot-starter-websocket'
@Configuration(proxyBeanMethods=false)
publicclassJavaxWebSocketConfiguration{

@Bean
publicServerEndpointExporterserverEndpointExporter(){
returnnewServerEndpointExporter();
}
}

依賴Spring的WebSocket模塊,手動(dòng)注入ServerEndpointExporter就可以了

需要注意ServerEndpointExporter是Spring中的類,算是Spring為了支持javax.websocket的原生用法所提供的支持類

冷知識(shí)

javax.websocket庫中定義了PongMessage而沒有PingMessage

通過我的測(cè)試發(fā)現(xiàn)基本上所有的WebSocket包括前端js自帶的,都實(shí)現(xiàn)了自動(dòng)回復(fù);也就是說當(dāng)接收到一個(gè)ping消息之后,是會(huì)自動(dòng)回應(yīng)一個(gè)pong消息,所以沒有必要再自己接受ping消息來處理了,即我們不會(huì)接受到ping消息

當(dāng)然我上面講的ping和pong都是需要使用框架提供的api,如果是我們自己通過Message來自定義心跳數(shù)據(jù)的話是沒有任何的處理的,下面是對(duì)應(yīng)的api

//發(fā)送ping
session.getAsyncRemote().sendPing(ByteBufferbuffer);

//發(fā)送pong
session.getAsyncRemote().sendPong(ByteBufferbuffer);

然后我又發(fā)現(xiàn)js自帶的WebSocket是沒有發(fā)送ping的api的,所以是不是可以猜想當(dāng)初就是約定服務(wù)端發(fā)送ping,客戶端回復(fù)pong

客戶端

客戶端也是使用注解配置

第一步

@ClientEndpoint
publicclassJavaxWebSocketClientEndpoint{

@OnOpen
publicvoidonOpen(Sessionsession){
//連接建立
}

@OnClose
publicvoidonClose(Sessionsession,CloseReasonreason){
//連接關(guān)閉
}

@OnMessage
publicvoidonMessage(Sessionsession,Stringmessage){
//接收文本消息
}

@OnMessage
publicvoidonMessage(Sessionsession,PongMessagemessage){
//接收pong消息
}

@OnMessage
publicvoidonMessage(Sessionsession,ByteBuffermessage){
//接收二進(jìn)制消息
}

@OnError
publicvoidonError(Sessionsession,Throwablee){
//異常處理
}
}

客戶端使用@ClientEndpoint來標(biāo)記,其他的@OnOpen,@OnClose,@OnMessage,@OnError和服務(wù)端一模一樣

第二步

WebSocketContainercontainer=ContainerProvider.getWebSocketContainer();
Sessionsession=container.connectToServer(JavaxWebSocketClientEndpoint.class,uri);

我們可以通過ContainerProvider來獲得一個(gè)WebSocketContainer,然后調(diào)用connectToServer方法將我們的客戶端類和連接的uri傳入就行了

冷知識(shí)

通過ContainerProvider#getWebSocketContainer獲得WebSocketContainer其實(shí)是基于SPI實(shí)現(xiàn)的

在Spring的環(huán)境中我更推薦大家使用ServletContextAware來獲得,代碼如下

@Component
publicclassJavaxWebSocketContainerimplementsServletContextAware{

privatevolatileWebSocketContainercontainer;

publicWebSocketContainergetContainer(){
if(container==null){
synchronized(this){
if(container==null){
container=ContainerProvider.getWebSocketContainer();
}
}
}
returncontainer;
}

@Override
publicvoidsetServletContext(@NonNullServletContextservletContext){
if(container==null){
container=(WebSocketContainer)servletContext
.getAttribute("javax.websocket.server.ServerContainer");
}
}
}

發(fā)消息

Sessionsession=...

//發(fā)送文本消息
session.getAsyncRemote().sendText(Stringmessage);

//發(fā)送二進(jìn)制消息
session.getAsyncRemote().sendBinary(ByteBuffermessage);

//發(fā)送對(duì)象消息,會(huì)嘗試使用Encoder編碼
session.getAsyncRemote().sendObject(Objectmessage);

//發(fā)送ping
session.getAsyncRemote().sendPing(ByteBufferbuffer);

//發(fā)送pong
session.getAsyncRemote().sendPong(ByteBufferbuffer);

WebMVC

依賴肯定是必不可少的

implementation'org.springframework.boot:spring-boot-starter-websocket'

服務(wù)端

第一步

importorg.springframework.web.socket.WebSocketHandler;
importorg.springframework.web.socket.WebSocketMessage;
importorg.springframework.web.socket.WebSocketSession;

publicclassServletWebSocketServerHandlerimplementsWebSocketHandler{

@Override
publicvoidafterConnectionEstablished(@NonNullWebSocketSessionsession)throwsException{
//連接建立
}

@Override
publicvoidhandleMessage(@NonNullWebSocketSessionsession,@NonNullWebSocketMessagemessage)throwsException{
//接收消息
}

@Override
publicvoidhandleTransportError(@NonNullWebSocketSessionsession,@NonNullThrowableexception)throwsException{
//異常處理
}

@Override
publicvoidafterConnectionClosed(@NonNullWebSocketSessionsession,@NonNullCloseStatuscloseStatus)throwsException{
//連接關(guān)閉
}

@Override
publicbooleansupportsPartialMessages(){
//是否支持接收不完整的消息
returnfalse;
}
}

我們實(shí)現(xiàn)一個(gè)WebSocketHandler來處理WebSocket的連接,關(guān)閉,消息和異常

第二步

@Configuration
@EnableWebSocket
publicclassServletWebSocketServerConfigurerimplementsWebSocketConfigurer{

@Override
publicvoidregisterWebSocketHandlers(@NonNullWebSocketHandlerRegistryregistry){
registry
//添加處理器到對(duì)應(yīng)的路徑
.addHandler(newServletWebSocketServerHandler(),"/websocket")
.setAllowedOrigins("*");
}
}

首先需要添加@EnableWebSocket來啟用WebSocket

然后實(shí)現(xiàn)WebSocketConfigurer來注冊(cè)WebSocket路徑以及對(duì)應(yīng)的WebSocketHandler

握手?jǐn)r截

提供了HandshakeInterceptor來攔截握手

@Configuration
@EnableWebSocket
publicclassServletWebSocketServerConfigurerimplementsWebSocketConfigurer{

@Override
publicvoidregisterWebSocketHandlers(@NonNullWebSocketHandlerRegistryregistry){
registry
//添加處理器到對(duì)應(yīng)的路徑
.addHandler(newServletWebSocketServerHandler(),"/websocket")
//添加握手?jǐn)r截器
.addInterceptors(newServletWebSocketHandshakeInterceptor())
.setAllowedOrigins("*");
}

publicstaticclassServletWebSocketHandshakeInterceptorimplementsHandshakeInterceptor{

@Override
publicbooleanbeforeHandshake(ServerHttpRequestrequest,ServerHttpResponseresponse,WebSocketHandlerwsHandler,Mapattributes)throwsException{
//握手之前
//繼續(xù)握手返回true,中斷握手返回false
returnfalse;
}

@Override
publicvoidafterHandshake(ServerHttpRequestrequest,ServerHttpResponseresponse,WebSocketHandlerwsHandler,Exceptionexception){
//握手之后
}
}
}

冷知識(shí)

我在集成的時(shí)候發(fā)現(xiàn)這種方式?jīng)]辦法動(dòng)態(tài)匹配路徑,它的路徑就是固定的,沒辦法使用如/websocket/**這樣的通配符

我在研究了一下之后發(fā)現(xiàn)可以在UrlPathHelper上做點(diǎn)文章

@Configuration
@EnableWebSocket
publicclassServletWebSocketServerConfigurerimplementsWebSocketConfigurer{

@Override
publicvoidregisterWebSocketHandlers(@NonNullWebSocketHandlerRegistryregistry){
if(registryinstanceofServletWebSocketHandlerRegistry){
//替換UrlPathHelper
((ServletWebSocketHandlerRegistry)registry)
.setUrlPathHelper(newPrefixUrlPathHelper("/websocket"));
}

registry
//添加處理器到對(duì)應(yīng)的路徑
.addHandler(newServletWebSocketServerHandler(),"/websocket/**")
.setAllowedOrigins("*");
}

publicclassPrefixUrlPathHelperextendsUrlPathHelper{

privateStringprefix;

@Override
public@NonNullStringresolveAndCacheLookupPath(@NonNullHttpServletRequestrequest){
//獲得原本的Path
Stringpath=super.resolveAndCacheLookupPath(request);
//如果是指定前綴就返回對(duì)應(yīng)的通配路徑
if(path.startsWith(prefix)){
returnprefix+"/**";
}
returnpath;
}
}
}

因?yàn)樗鼉?nèi)部實(shí)際上就是用一個(gè)Map來存的,所以沒有辦法用通配符

主要是有現(xiàn)成的AntPathMatcher實(shí)現(xiàn)通配應(yīng)該不麻煩才對(duì)啊

客戶端

第一步

publicclassServletWebSocketClientHandlerimplementsWebSocketHandler{

@Override
publicvoidafterConnectionEstablished(@NonNullWebSocketSessionsession)throwsException{
//連接建立
}

@Override
publicvoidhandleMessage(@NonNullWebSocketSessionsession,@NonNullWebSocketMessagemessage)throwsException{
//接收消息
}

@Override
publicvoidhandleTransportError(@NonNullWebSocketSessionsession,@NonNullThrowableexception)throwsException{
//異常處理
}

@Override
publicvoidafterConnectionClosed(@NonNullWebSocketSessionsession,@NonNullCloseStatuscloseStatus)throwsException{
//連接關(guān)閉
}

@Override
publicbooleansupportsPartialMessages(){
//是否支持接收不完整的消息
returnfalse;
}
}

和服務(wù)端一樣我們需要先實(shí)現(xiàn)一個(gè)WebSocketHandler來處理WebSocket的連接,關(guān)閉,消息和異常

第二步

WebSocketClientclient=newStandardWebSocketClient();
WebSocketHandlerhandler=newServletWebSocketClientHandler();
WebSocketConnectionManagermanager=newWebSocketConnectionManager(client,handler,uri);
manager.start();

首先我們需要先new一個(gè)StandardWebSocketClient,可以傳入一個(gè)WebSocketContainer參數(shù),獲得該對(duì)象的方式我之前已經(jīng)介紹過了,這邊就先略過

然后new一個(gè)WebSocketConnectionManager傳入WebSocketClient,WebSocketHandler還有路徑uri

最后調(diào)用一下WebSocketConnectionManager的start方法就可以啦

冷知識(shí)

這里如果大家去看WebSocketClient的實(shí)現(xiàn)類就會(huì)發(fā)現(xiàn)有StandardWebSocketClient還有JettyWebSocketClient等等,所以大家可以根據(jù)自身項(xiàng)目所使用的容器來選擇不同的WebSocketClient實(shí)現(xiàn)類

這里給大家貼一小段Spring適配不同容器WebSocket的代碼

publicabstractclassAbstractHandshakeHandlerimplementsHandshakeHandler,Lifecycle{

privatestaticfinalbooleantomcatWsPresent;

privatestaticfinalbooleanjettyWsPresent;

privatestaticfinalbooleanjetty10WsPresent;

privatestaticfinalbooleanundertowWsPresent;

privatestaticfinalbooleanglassfishWsPresent;

privatestaticfinalbooleanweblogicWsPresent;

privatestaticfinalbooleanwebsphereWsPresent;

static{
ClassLoaderclassLoader=AbstractHandshakeHandler.class.getClassLoader();
tomcatWsPresent=ClassUtils.isPresent(
"org.apache.tomcat.websocket.server.WsHttpUpgradeHandler",classLoader);
jetty10WsPresent=ClassUtils.isPresent(
"org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer",classLoader);
jettyWsPresent=ClassUtils.isPresent(
"org.eclipse.jetty.websocket.server.WebSocketServerFactory",classLoader);
undertowWsPresent=ClassUtils.isPresent(
"io.undertow.websockets.jsr.ServerWebSocketContainer",classLoader);
glassfishWsPresent=ClassUtils.isPresent(
"org.glassfish.tyrus.servlet.TyrusHttpUpgradeHandler",classLoader);
weblogicWsPresent=ClassUtils.isPresent(
"weblogic.websocket.tyrus.TyrusServletWriter",classLoader);
websphereWsPresent=ClassUtils.isPresent(
"com.ibm.websphere.wsoc.WsWsocServerContainer",classLoader);
}
}

發(fā)消息

importorg.springframework.web.socket.*;

WebSocketSessionsession=...

//發(fā)送文本消息
session.sendMessage(newTextMessage(CharSequencemessage);

//發(fā)送二進(jìn)制消息
session.sendMessage(newBinaryMessage(ByteBuffermessage));

//發(fā)送ping
session.sendMessage(newPingMessage(ByteBuffermessage));

//發(fā)送pong
session.sendMessage(newPongMessage(ByteBuffermessage));

WebFlux

WebFlux的WebSocket不需要額外的依賴包

服務(wù)端

第一步

importorg.springframework.web.reactive.socket.WebSocketHandler;
importorg.springframework.web.reactive.socket.WebSocketSession;

publicclassReactiveWebSocketServerHandlerimplementsWebSocketHandler{

@NonNull
@Override
publicMonohandle(WebSocketSessionsession){
Monosend=session.send(Flux.create(sink->{
//可以持有sink對(duì)象在任意時(shí)候調(diào)用next發(fā)送消息
sink.next(WebSocketMessagemessage);
})).doOnError(it->{
//異常處理
});

Monoreceive=session.receive()
.doOnNext(it->{
//接收消息
})
.doOnError(it->{
//異常處理
})
.then();

@SuppressWarnings("all")
Disposabledisposable=session.closeStatus()
.doOnError(it->{
//異常處理
})
.subscribe(it->{
//連接關(guān)閉
});

returnMono.zip(send,receive).then();
}
}

首先需要注意這里的WebSocketHandler和WebSocketSession是reactive包下的

通過WebSocketSession#send方法來持有一個(gè)FluxSink來用于發(fā)送消息

通過WebSocketSession#receive來訂閱消息

通過WebSocketSession#closeStatus來訂閱連接關(guān)閉事件

第二步

@Component
publicclassReactiveWebSocketServerHandlerMappingextendsSimpleUrlHandlerMapping{

publicReactiveWebSocketServerHandlerMapping(){
Mapmap=newHashMap<>();
map.put("/websocket/**",newReactiveWebSocketServerHandler());
setUrlMap(map);
setOrder(100);
}
}

注冊(cè)一個(gè)HandlerMapping同時(shí)配置路徑和對(duì)應(yīng)的WebSocketHandler

第三步

@Configuration(proxyBeanMethods=false)
publicclassReactiveWebSocketConfiguration{

@Bean
publicWebSocketHandlerAdapterwebSocketHandlerAdapter(){
returnnewWebSocketHandlerAdapter();
}
}

注入WebSocketHandlerAdapter

冷知識(shí)

我們自定義的HandlerMapping需要設(shè)置order,如果不設(shè)置,默認(rèn)為Ordered.LOWEST_PRECEDENCE,會(huì)導(dǎo)致這個(gè)HandlerMapping被放在最后,當(dāng)有客戶端連接上來時(shí)會(huì)被其他的HandlerMapping優(yōu)先匹配上而連接失敗

客戶端

第一步

publicclassReactiveWebSocketClientHandlerimplementsWebSocketHandler{

@NonNull
@Override
publicMonohandle(WebSocketSessionsession){
Monosend=session.send(Flux.create(sink->{
//可以持有sink對(duì)象在任意時(shí)候調(diào)用next發(fā)送消息
sink.next(WebSocketMessagemessage);
})).doOnError(it->{
//處理異常
});

Monoreceive=session.receive()
.doOnNext(it->{
//接收消息
})
.doOnError(it->{
//異常處理
})
.then();

@SuppressWarnings("all")
Disposabledisposable=session.closeStatus()
.doOnError(it->{
//異常處理
})
.subscribe(it->{
//連接關(guān)閉
});

returnMono.zip(send,receive).then();
}
}

客戶端WebSocketHandler的寫法和服務(wù)端的一樣

第二步

importorg.springframework.web.reactive.socket.client.WebSocketClient;

WebSocketClientclient=ReactorNettyWebSocketClient();
WebSocketHandlerhandler=newReactiveWebSocketClientHandler();
client.execute(uri,handler).subscribe();

首先我們需要先new一個(gè)ReactorNettyWebSocketClient

然后調(diào)用一下WebSocketClient的execute方法傳入路徑uri和WebSocketHandler并繼續(xù)調(diào)用subscribe方法就行啦

冷知識(shí)

和WebMVC中的WebSocketClient一樣,Reactive包中的WebSocketClient也有很多實(shí)現(xiàn)類,比如ReactorNettyWebSocketClient,JettyWebSocketClient,UndertowWebSocketClient,TomcatWebSocketClient等等,也是需要大家基于自身項(xiàng)目的容器使用不同的實(shí)現(xiàn)類

這里也給大家貼一小段Reactive適配不同容器WebSocket的代碼

publicclassHandshakeWebSocketServiceimplementsWebSocketService,Lifecycle{

privatestaticfinalbooleantomcatPresent;

privatestaticfinalbooleanjettyPresent;

privatestaticfinalbooleanjetty10Present;

privatestaticfinalbooleanundertowPresent;

privatestaticfinalbooleanreactorNettyPresent;

static{
ClassLoaderloader=HandshakeWebSocketService.class.getClassLoader();
tomcatPresent=ClassUtils.isPresent("org.apache.tomcat.websocket.server.WsHttpUpgradeHandler",loader);
jettyPresent=ClassUtils.isPresent("org.eclipse.jetty.websocket.server.WebSocketServerFactory",loader);
jetty10Present=ClassUtils.isPresent("org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer",loader);
undertowPresent=ClassUtils.isPresent("io.undertow.websockets.WebSocketProtocolHandshakeHandler",loader);
reactorNettyPresent=ClassUtils.isPresent("reactor.netty.http.server.HttpServerResponse",loader);
}
}

發(fā)消息

我們需要使用在WebSocketHandler中獲得的FluxSink來發(fā)送消息

importorg.springframework.web.reactive.socket.CloseStatus;
importorg.springframework.web.reactive.socket.WebSocketMessage;
importorg.springframework.web.reactive.socket.WebSocketSession;

publicclassReactiveWebSocket{

privatefinalWebSocketSessionsession;

privatefinalFluxSinksender;

publicReactiveWebSocket(WebSocketSessionsession,FluxSinksender){
this.session=session;
this.sender=sender;
}

publicStringgetId(){
returnsession.getId();
}

publicURIgetUri(){
returnsession.getHandshakeInfo().getUri();
}

publicvoidsend(Objectmessage){
if(messageinstanceofWebSocketMessage){
sender.next((WebSocketMessage)message);
}elseif(messageinstanceofString){
//發(fā)送文本消息
sender.next(session.textMessage((String)message));
}elseif(messageinstanceofDataBuffer){
//發(fā)送二進(jìn)制消息
sender.next(session.binaryMessage(factory->(DataBuffer)message));
}elseif(messageinstanceofByteBuffer){
發(fā)送二進(jìn)制消息
sender.next(session.binaryMessage(factory->factory.wrap((ByteBuffer)message)));
}elseif(messageinstanceofbyte[]){
發(fā)送二進(jìn)制消息
sender.next(session.binaryMessage(factory->factory.wrap((byte[])message)));
}else{
thrownewIllegalArgumentException("Messagetypenotmatch");
}
}

publicvoidping(){
//發(fā)送ping
sender.next(session.pingMessage(factory->factory.wrap(ByteBuffer.allocate(0))));
}

publicvoidpong(){
//發(fā)送pong
sender.next(session.pongMessage(factory->factory.wrap(ByteBuffer.allocate(0))));
}

publicvoidclose(CloseStatusreason){
sender.complete();
session.close(reason).subscribe();
}
}

Java-WebSocket

這是一個(gè)純java的第三方庫,專門用于實(shí)現(xiàn)WebSocket

SocketIO

該庫使用的協(xié)議是經(jīng)過自己封裝的,支持很多的語言,提供了統(tǒng)一的接口,所以需要使用它提供的Server和Client來連接,如socket.io-server-java和socket.io-client-java

這個(gè)庫我了解下來主要用于實(shí)時(shí)聊天等場(chǎng)景,所以如果只是普通的WebSocket功能就有點(diǎn)大材小用了

Netty

這個(gè)大家應(yīng)該都比較熟悉了,就算沒用過肯定也聽過

網(wǎng)上的文檔和示例也非常多,我這里就不介紹有的沒的了,Github傳送門。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 二進(jìn)制
    +關(guān)注

    關(guān)注

    2

    文章

    786

    瀏覽量

    41564
  • JAVA語言
    +關(guān)注

    關(guān)注

    0

    文章

    138

    瀏覽量

    20062
  • 緩存器
    +關(guān)注

    關(guān)注

    0

    文章

    63

    瀏覽量

    11641
  • WebSocket
    +關(guān)注

    關(guān)注

    0

    文章

    28

    瀏覽量

    3725

原文標(biāo)題:WebSocket 的 6 種集成方式

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    淺談集成FPGA的兩方式:eFPGA(SoC)&amp; cFPGA(SiP)

    目前流行的兩集成方案分別是embedded FPGA(以下簡(jiǎn)稱eFPGA集成方案)以及FPGA Chiplets(以下簡(jiǎn)稱cFPGA集成方案)1.eFPGA
    的頭像 發(fā)表于 08-16 09:53 ?7070次閱讀
    淺談<b class='flag-5'>集成</b>FPGA的兩<b class='flag-5'>種</b><b class='flag-5'>方式</b>:eFPGA(SoC)&amp; cFPGA(SiP)

    白光LED形成方式

    白光LED形成方式
    發(fā)表于 08-20 21:15

    ORCAD與PLM集成方

    ORCAD與PLM集成方
    發(fā)表于 07-07 14:59

    求一基于FPGA的A型數(shù)字式超聲系統(tǒng)的構(gòu)成方式

    簡(jiǎn)略介紹了超聲探傷的基本原理,并在此基礎(chǔ)上提出了一基于FPGA的A型數(shù)字式超聲系統(tǒng)的構(gòu)成方式,著重介紹了系統(tǒng)的硬件構(gòu)成。其中,基于FPGA的數(shù)字信號(hào)處理模塊從根本上解決了傳統(tǒng)A型探傷
    發(fā)表于 05-06 08:38

    SPWM信號(hào)主要有3成方式

    描述目前,SPWM信號(hào)主要有3成方式:1)使用比較器、振蕩器等模擬電路產(chǎn)生三角波和方波進(jìn)行比較,產(chǎn)生SPWM波,但是此種方法電路復(fù)雜,受元器件精度影響大,且不易控制;2)利用專用SPWM集成芯片
    發(fā)表于 11-15 08:01

    基于TCP的一新的網(wǎng)絡(luò)協(xié)議WebSocket

    開啟 WebSocket 服務(wù)WebSocket 服務(wù)是網(wǎng)頁程序、安卓 App、微信小程序等獲得數(shù)據(jù)和服務(wù)的接口,是基于TCP 的一新的網(wǎng)絡(luò)協(xié)議,它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信。通過
    發(fā)表于 12-16 07:38

    RK集成系統(tǒng)apk的集成方式該怎樣去實(shí)現(xiàn)呢

    RK集成系統(tǒng)apk相對(duì)于MTK的集成方式有何優(yōu)點(diǎn)?RK集成系統(tǒng)apk的集成方式該怎樣去實(shí)現(xiàn)呢?
    發(fā)表于 02-18 07:44

    基于凸殼算法的SVM集成方

    為提高支持向量機(jī)(SVM)集成的訓(xùn)練速度,提出一基于凸殼算法的SVM 集成方法,得到訓(xùn)練集各類數(shù)據(jù)的殼向量,將其作為基分類器的訓(xùn)練集,并采用Bagging 策略集成各個(gè)SVM。在訓(xùn)
    發(fā)表于 04-16 11:43 ?10次下載

    智能建筑系統(tǒng)集成方式的研究及應(yīng)用

    本文通過闡述智能建筑系統(tǒng)集成層次劃分的概念,分析了現(xiàn)存的四種系統(tǒng)集成方式的特點(diǎn)及存在的問題,提出了模塊并行集成模式和基于OPC 的組件化集成模式兩
    發(fā)表于 06-16 11:32 ?17次下載

    BACnet網(wǎng)絡(luò)與Internet的集成方

    BACnet是開放的樓宇設(shè)備自動(dòng)控制網(wǎng)絡(luò)數(shù)據(jù)通信協(xié)議。隨著Internet在通信領(lǐng)域的發(fā)展,控制網(wǎng)絡(luò)與Internet的集成已是必然趨勢(shì)。本文給出了一BACnet-TCP/IP集成方案,并詳細(xì)敘述了方
    發(fā)表于 02-22 11:34 ?27次下載

    語音合成方式與原理電路圖

    語音合成方式與原理電路圖
    發(fā)表于 07-20 11:53 ?623次閱讀
    語音合<b class='flag-5'>成方式</b>與原理電路圖

    WebSocket有什么優(yōu)點(diǎn)

    WebSocket是一在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。WebSocket通信協(xié)議于2011年被IETF定為標(biāo)準(zhǔn)RFC 6455,并由RFC7936補(bǔ)充規(guī)范。WebSocket
    的頭像 發(fā)表于 02-15 15:53 ?8239次閱讀
    <b class='flag-5'>WebSocket</b>有什么優(yōu)點(diǎn)

    鴻蒙上WebSocket的使用方法

    WebSocket 是一網(wǎng)絡(luò)通訊協(xié)議,很多網(wǎng)絡(luò)開發(fā)工作者都需要它。本文介紹在 OpenHarmony 上 WebSocket 協(xié)議的使用方法。
    的頭像 發(fā)表于 03-08 14:17 ?1745次閱讀

    websocket協(xié)議的原理

    WebSocket協(xié)議是基于TCP的一新的網(wǎng)絡(luò)協(xié)議。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工(full-duplex)通信——允許服務(wù)器主動(dòng)發(fā)送信息給客戶端。 WebSocket通信協(xié)議于2011年被IETF
    的頭像 發(fā)表于 11-09 15:13 ?1058次閱讀
    <b class='flag-5'>websocket</b>協(xié)議的原理

    萬界星空科技MES數(shù)據(jù)的集成方式

    MES系統(tǒng)與其他系統(tǒng)常見的集成方式。根據(jù)實(shí)際需求和系統(tǒng)環(huán)境,選擇適合的集成方式可以實(shí)現(xiàn)不同系統(tǒng)之間的協(xié)同工作,提高生產(chǎn)效率和管理水平。具體的集成方式可能因企業(yè)和行業(yè)的不同而有所差異。
    的頭像 發(fā)表于 10-09 15:30 ?98次閱讀
    萬界星空科技MES數(shù)據(jù)的<b class='flag-5'>集成方式</b>