首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java-WebSocket vs Netty-WebSocket 资源占用

Java-WebSocket vs Netty-WebSocket 资源占用

作者头像
FunTester
发布于 2023-10-10 06:11:06
发布于 2023-10-10 06:11:06
74900
代码可运行
举报
文章被收录于专栏:FunTesterFunTester
运行总次数:0
代码可运行

在进行WebSocket协议连接或者WebSocket接口测试的时候,一旦遇到超大连接数量的场景中时,之前使用过的实现 Java-WebSocket 以及 Netty-WebSocket 两种实现就会显示出巨大的性能差距。当然 Netty-WebSocket 就是为了解决性能问题而来的。

so,今天我就来展示一下两个 WebSocket 实现在使用中具体的差异,本文集中在资源占用上,特别是线程占用。

理论差异

Java-WebSocket

据可靠资料显示,两者的差异主要以在管理 WebSocket 连接时使用的线程数不同,以下是使用org.java_websocket.client.WebSocketClient创建WebSocket客户端时,它会创建以下几个线程:

  • 「ConnectThread(连接线程)」:当你调用WebSocketClient.connect()方法时,WebSocket客户端会创建一个单独的线程来处理连接建立的过程。这个线程负责建立实际的WebSocket连接。
  • 「WriteThread(写线程)」:WebSocket客户端还会创建一个单独的线程,用于发送WebSocket消息。当你调用WebSocket.send()方法发送消息时,消息将被发送到这个线程,然后由该线程负责将消息写入到底层的WebSocket连接中。
  • 「ReadThread(读线程)」:WebSocket客户端会创建一个用于接收WebSocket消息的线程。这个线程会持续监听来自WebSocket服务器的消息,并在接收到消息时触发相应的事件处理器。

这些线程的存在使得WebSocket客户端能够在后台处理连接、发送和接收消息,而不会阻塞主线程。这有助于确保应用程序在与WebSocket服务器进行通信时能够保持响应性。

据资料显示不同版本的实现线程是不一样的,这里我没有找到具体的版本差异,也没有进行测试。

Netty-WebSocket

Netty其实并不存在上面这个问题,因为WebSocket连接和线程数并没有强的绑定关系。Netty只有一个处理事件的 io.netty.channel.EventLoopGroup 需要使用线程池设计,其他均没有设置线程和创建线程的设置。

被测服务

这里我用Go写了一个 WebSocket 的服务端,一来省事儿,二来性能高足以应付接下来的测试。服务端代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// CreateServer  
// @Description: 重建一个WebSocket服务  
// @param port 端口  
// @param path 路径  
func CreateServer(port int, path string) {  
  
   var upgrader = websocket.Upgrader{  
      ReadBufferSize:   1024,  
      WriteBufferSize:  1024,  
      HandshakeTimeout: 5 * time.Second,  
   }  
  
   http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {  
      conn, _ := upgrader.Upgrade(w, r, nil)  
      conn.WriteMessage(websocket.TextMessage, []byte("msg"))  
  
      for {  
         msgType, msg, err := conn.ReadMessage()  
         if err != nil {  
            log.Println(err)  
            return  
         }  
         fmt.Printf("%s receive: %s\n", conn.RemoteAddr(), string(msg))  
  
         if err = conn.WriteMessage(msgType, msg); err != nil {  
            log.Println("ffahv")  
            return  
         }  
      }  
   })  
  
   http.ListenAndServe(":"+strconv.Itoa(port), nil)  
}

单链接对比

空Java进程

首先测试一下空的Java进行消耗的线程数详情,测试客户端如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.funtester.frame.SourceCode  
  
class Empty extends SourceCode{  
  
    static void main(String[] args) {  
        waitForKey("按任意键退出")  
    }  
      
  
}

运行时,进行监控:

空Java进行

Java-WebSocket

只创建1个WebSocket客户端,测试代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.funtest.websocket

import com.funtester.frame.SourceCode
import com.funtester.socket.WebSocketFunClient

class WebSocket extends SourceCode {

    static String url = "ws://localhost:12345/test"


    static void main(String[] args) {
        def instance = WebSocketFunClient.getInstance(url)
        instance.connect()
        instance.send("Hello FunTester")
        waitForKey("按任意键退出")
    }
}

运行线程监控:

WebSocket单线程

Netty-WebSocket

逻辑同上,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.funtest.websocket

import com.funtester.frame.SourceCode
import com.funtester.socket.netty.WebSocketConnector
import groovy.util.logging.Log4j2

@Log4j2
class NettySocket extends SourceCode {

    static void main(String[] args) {
        String serverIp = "ws://127.0.0.1";
        int serverPort = 12345;
        def h = {String x ->
            log.info("收到消息:{}", x)
        }
        WebSocketConnector client = new WebSocketConnector(serverIp, serverPort, "/test",h)
        client.connect()
        client.getHandshakeFuture().get()
        client.sendText("Hello FunTester").get()
        waitForKey("按任意键退出")
    }
}

运行时线程监控:

Netty-WebSocket

结论

Java-WebSocket额外创建了3个线程,而Netty-WebSocket额外创建了1个线程。这里我采取了默认的 io.netty.channel.EventLoopGroup 创建策略。

1000连接

Netty-WebSocket

测试代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.funtest.websocket  
  
import com.funtester.frame.SourceCode  
import com.funtester.socket.netty.WebSocketConnector  
import groovy.util.logging.Log4j2  
  
@Log4j2  
class NettySocket extends SourceCode {  
  
    static void main(String[] args) {  
        String serverIp = "ws://127.0.0.1";  
        int serverPort = 12345;  
        def h = {String x ->  
            log.info("收到消息:{}", x)  
        }  
        1000.times {  
            WebSocketConnector client = new WebSocketConnector(serverIp, serverPort, "/test", h)  
            client.connect()  
            client.getHandshakeFuture().get()  
            client.sendText("Hello FunTester").get()  
        }  
        waitForKey("按任意键退出")  
    }  
}

运行时线程监控:

Netty1000连接

Java-WebSocket

由于创建实在太慢了,我测试了100个连接,测试代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.funtest.websocket  
  
import com.funtester.frame.SourceCode  
import com.funtester.socket.WebSocketFunClient  
  
class WebSocket extends SourceCode {  
  
    static String url = "ws://localhost:12345/test"  
  
  
    static void main(String[] args) {  
        100.times {  
            fun {  
                def instance = WebSocketFunClient.getInstance(url)  
                instance.connect()  
                instance.send("Hello FunTester")  
            }  
        }        waitForKey("按任意键退出")  
    }  
}

运行时线程监控:

WebSocket1000连接

Netty极限

如果我们只是单纯测试连接数量的话,并没有必要创建很多处理WebSocket事件的线程,我们可以直接写死成1个线程。下面是测试结果:

Netty极限1000连接

结论

Netty稳如狗!

代码更新

在本次的实践中,我对Netty-WebSocket的实现又做了一批更新,主要增加WebSocket接口路径和消息处理闭包功能,并且偷偷修复了BUG。

WebSocketConnector

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.funtester.socket.netty  
  
import com.funtester.frame.execute.ThreadPoolUtil  
import groovy.util.logging.Log4j2  
import io.netty.bootstrap.Bootstrap  
import io.netty.channel.*  
import io.netty.channel.group.ChannelGroup  
import io.netty.channel.group.DefaultChannelGroup  
import io.netty.channel.nio.NioEventLoopGroup  
import io.netty.channel.socket.SocketChannel  
import io.netty.channel.socket.nio.NioSocketChannel  
import io.netty.handler.codec.http.DefaultHttpHeaders  
import io.netty.handler.codec.http.HttpClientCodec  
import io.netty.handler.codec.http.HttpObjectAggregator  
import io.netty.handler.codec.http.websocketx.*  
import io.netty.handler.stream.ChunkedWriteHandler  
import io.netty.util.concurrent.GlobalEventExecutor  
  
@Log4j2  
class WebSocketConnector {  
  
    static Bootstrap bootstrap = new Bootstrap()  
  
    /**  
     * 处理事件的线程池  
     */  
    static EventLoopGroup group = new NioEventLoopGroup(ThreadPoolUtil.getFactory("N"))  
  
    static {  
        bootstrap.group(group).channel(NioSocketChannel.class)  
    }  
  
    /**  
     * 用于记录和管理所有客户端的channel  
     */    static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE)  
  
    WebSocketClientHandshaker handShaker  
  
    ChannelPromise handshakeFuture  
  
    String host  
  
    int port  
  
    String path  
  
    /**  
     * 网络通道  
     */  
    Channel channel  
  
    WebSocketIoHandler handler  
  
    /**  
     * WebSocket协议类型的模拟客户端连接器构造方法  
     *  
     * @param serverIp  
     * @param serverSocketPort  
     * @param group  
     */    WebSocketConnector(String host, int port, String path, Closure closure = null) {  
        this.host = host  
        this.port = port  
        this.path = path  
        String URL = this.host + ":" + this.port + path  
        URI uri = new URI(URL)  
        handler = new WebSocketIoHandler(WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, true, new DefaultHttpHeaders()))  
        if (closure != null) handler.closure = closure  
        bootstrap.option(ChannelOption.TCP_NODELAY, true)  
                .option(ChannelOption.SO_KEEPALIVE, true)  
                .handler(new ChannelInitializer<SocketChannel>() {  
  
                    @Override  
                    protected void initChannel(SocketChannel ch) throws Exception {  
                        ChannelPipeline pipeline = ch.pipeline()  
                        pipeline.addLast(new HttpClientCodec())  
                        pipeline.addLast(new ChunkedWriteHandler())  
                        pipeline.addLast(new HttpObjectAggregator(1024 * 1024))  
                        pipeline.addLast(handler)  
                    }  
                })  
    }  
  
  
    /**  
     * 连接  
     */  
    void connect() {  
        try {  
            try {  
                ChannelFuture future = bootstrap.connect(this.host - "ws://" - "wss://", this.port).sync()  
                this.channel = future.channel()  
                clients.add(channel)  
            } catch (e) {  
                log.error("创建channel失败", e)  
            }  
        } catch (Exception e) {  
            log.error("连接服务失败", e)  
        } finally {  
            this.handshakeFuture = handler.handshakeFuture()  
        }  
    }  
  
    /**  
     * 发送文本消息  
     */  
    ChannelFuture sendText(String msg) {  
        channel.writeAndFlush(new TextWebSocketFrame(msg))  
    }  
  
    /**  
     * 发送ping消息  
     */  
    ChannelFuture ping() {  
        channel.writeAndFlush(new PingWebSocketFrame())  
    }  
  
    /**  
     * 关闭  
     */  
    void close() {  
        group.shutdownGracefully()  
    }  
  
}

WebSocketIoHandler

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.funtester.socket.netty  
  
import groovy.util.logging.Log4j2  
import io.netty.channel.*  
import io.netty.channel.group.ChannelGroup  
import io.netty.channel.group.DefaultChannelGroup  
import io.netty.handler.codec.http.FullHttpResponse  
import io.netty.handler.codec.http.websocketx.*  
import io.netty.handler.timeout.IdleState  
import io.netty.handler.timeout.IdleStateEvent  
import io.netty.util.concurrent.GlobalEventExecutor  
  
/**  
 * WebSocket协议类型的模拟客户端IO处理器类  
 */  
@Log4j2  
class WebSocketIoHandler extends SimpleChannelInboundHandler<Object> {  
  
    /**  
     * 用于记录和管理所有客户端的channel  
     */    private ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE)  
  
    private final WebSocketClientHandshaker handShaker  
  
    Closure closure  
  
    private ChannelPromise handshakeFuture  
  
    WebSocketIoHandler(WebSocketClientHandshaker handShaker) {  
        this.handShaker = handShaker  
    }  
  
    ChannelFuture handshakeFuture() {  
        return handshakeFuture  
    }  
  
    @Override  
    void handlerAdded(ChannelHandlerContext ctx) {  
        handshakeFuture = ctx.newPromise()  
    }  
  
    @Override  
    void channelActive(ChannelHandlerContext ctx) {  
        handShaker.handshake(ctx.channel());  
    }  
  
    @Override  
    void channelInactive(ChannelHandlerContext ctx) {  
        ctx.close()  
        try {  
            super.channelInactive(ctx)  
        } catch (Exception e) {  
            log.error("channelInactive 异常.", e)  
        }  
        log.warn("WebSocket链路与服务器连接已断开.")  
    }  
  
    @Override  
    void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {  
        Channel ch = ctx.channel()  
        if (!handShaker.isHandshakeComplete()) {  
            try {  
                handShaker.finishHandshake(ch, (FullHttpResponse) msg)  
                handshakeFuture.setSuccess()  
            } catch (WebSocketHandshakeException e) {  
                log.warn("WebSocket Client failed to connect", e)  
                handshakeFuture.setFailure(e)  
            }  
            return  
        }  
  
        WebSocketFrame frame = (WebSocketFrame) msg  
        if (frame instanceof TextWebSocketFrame) {  
            if (closure != null) {  
                TextWebSocketFrame textFrame = (TextWebSocketFrame) frame  
                closure(textFrame.text())  
            }  
        } else if (frame instanceof CloseWebSocketFrame) {  
            log.info("WebSocket Client closing")  
            ch.close()  
        }  
    }  
  
    @Override  
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
        log.error("WebSocket链路由于发生异常,与服务器连接已断开.", cause)  
        if (!handshakeFuture.isDone()) {  
            handshakeFuture.setFailure(cause)  
        }  
        ctx.close()  
        super.exceptionCaught(ctx, cause)  
    }  
  
    @Override  
    void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {  
        if (evt instanceof IdleStateEvent) {  
            IdleStateEvent event = (IdleStateEvent) evt  
            // 如果写通道处于空闲状态,就发送心跳命令  
            if (IdleState.WRITER_IDLE == event.state() || IdleState.READER_IDLE == event.state()) {  
                // 发送心跳数据  
                def channel = ctx.channel()  
                channel.writeAndFlush(new TextWebSocketFrame("dsf"))  
            }  
        } else {  
            super.userEventTriggered(ctx, evt)  
        }  
    }  
}

FunTester原创专题推荐~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
7 条评论
热度
最新
真的写的很好! 经常听到docker多好,刚想尝试虚拟机上用docker部署感受一下,发现docker上还得再装OS,突然有种直觉很不对劲,跟虚拟机也没啥区别,还更浪费开销。找了很多问答,终于在你这把docker的真正价值点说清楚了,让我明白docker真用到的地方。就是为了自动化运维,方便快速迁移
真的写的很好! 经常听到docker多好,刚想尝试虚拟机上用docker部署感受一下,发现docker上还得再装OS,突然有种直觉很不对劲,跟虚拟机也没啥区别,还更浪费开销。找了很多问答,终于在你这把docker的真正价值点说清楚了,让我明白docker真用到的地方。就是为了自动化运维,方便快速迁移
回复回复点赞举报
“标准!”人家压根不是为了给你当虚拟机用的,人家是为了给启动生产环境的进程做标准化的!
“标准!”人家压根不是为了给你当虚拟机用的,人家是为了给启动生产环境的进程做标准化的!
回复回复点赞举报
“现实生活中你是几乎不可能看见两个神经正常的成年人争论到底是锤子更好还是螺丝刀更好这个问题的”笑哭
“现实生活中你是几乎不可能看见两个神经正常的成年人争论到底是锤子更好还是螺丝刀更好这个问题的”笑哭
回复回复点赞举报
允许摘抄吗,我会注明出处
允许摘抄吗,我会注明出处
回复回复点赞举报
厉害厉害!受益匪浅~
厉害厉害!受益匪浅~
回复回复点赞举报
深入浅出
深入浅出
回复回复点赞举报
感觉写很好啊,我是不是说了废话.
感觉写很好啊,我是不是说了废话.
回复回复点赞举报
推荐阅读
SSL证书价格差异
SSL证书市场品牌和种类众多,用户在选择证书的时候,也能随心所欲的购买到心仪的证书品牌类型。但是也有不少用户在选购的时候,也不禁有疑问:不同的证书品牌和类型为什么价格相差如此之大?确实,有的证书很便宜,甚至是免费使用,但是有的证书价格却高的出奇。出现这样情况的原因主要是由于品牌和证书类型,以及证书的售后服务方面的原因导致的。
JoySSL
2023/02/17
1.7K0
SSL证书价格差异
一文读懂,SSL证书怎么做验证?
SSL证书目前已经有越来越多的企业网站开始使用,安装SSL证书后,原有的http协议将会变成安全性更好的https加密协议,这对保护用户的信息安全,保障企业及用户的利益起着重要作用。
JoySSL
2023/03/20
1.1K0
一文读懂,SSL证书怎么做验证?
什么是SSL证书?为什么要买SSL证书?
SSL证书是数字证书的一种,类似于驾驶证、护照和营业执照的电子副本。因为配置在服务器上,也称为SSL服务器证书。
柳絮云泡泡
2023/02/24
6.3K0
什么是SSL证书?为什么要买SSL证书?
DV,OV,EV证书优势区别
互联网在国内最近20年的发展,使得网民数量迅速增长,很多用户在访问网站时,对使用HTTP协议已经习以为常,但随着时代的发展,网络技术的革新也是日新月异,HTTPS协议的诞生满足了用户对网站安全的需求,并且正日益成为网络安全领域的潮流和新趋势。
JoySSL
2023/02/03
1.7K0
DV,OV,EV证书优势区别
SSL证书类型
图片 SSL证书具有服务器身份认证和数据加密传输的重要作用,在国家政策和各大主流浏览器的推动下,SSL证书早已成为我国网站的标配。但对于大部分企业来说,在建设网站时所面临的问题并不是要不要安装SSL
柳絮云泡泡
2023/03/08
2.5K0
SSL证书类型
互联网十万个为什么之什么是SSL证书?
SSL证书是一种数字化的证书,用来创建加密连接和验证网站的身份是否可信。同时,为避免钓鱼网站、假冒正规网站骗取用户信息等安全威胁,主流浏览器会对未使用HTTPS的网站增加风险提示。
linus_lin
2024/09/25
2640
互联网十万个为什么之什么是SSL证书?
企业申请ssl证书选择OV还是EV?
几乎每隔一段时间,互联网中都会出现信息泄露的大事件,接着被广泛报道,深究其原因,很多都是因为服务器信息被窃取篡改造成的,如今随着技术的日异月新,对互联网信息泄露事件已经有了防范的措施,为网站安装SSL证书实现HTTPS加密已成为网站建设的必要条件。
柳絮云泡泡
2023/04/04
9670
企业申请ssl证书选择OV还是EV?
SSL证书杜绝安全隐患
据外媒报道,数字风险防护公司CloudSEK观察到,在大规模网络钓鱼活动中使用短链接的情况有所增加,同时,不法分子还借助反向隧道在本地托管网络钓鱼页面,以逃避防护系统检测。专家建议,为了防止此类威胁,用户应避免点击从未知或可疑来源收到的链接。
柳絮云泡泡
2023/03/09
1.4K0
SSL证书杜绝安全隐患
SSL证书的分类有哪些?如何选择合适的SSL证书?
为了保护网站数据和用户信息,很多企业开始为网站安装SSL证书,有效提升了网站安全性。那么SSL证书的分类有哪些?如何选择合适的SSL证书?
稀糊牛肉粥
2023/09/25
9700
怎么选择SSL证书?
看到HTTPS证书,可能很多人会觉得陌生,其实它就是SSL证书的另一种称谓,因为网站部署SSL证书后才能实现HTTPS链接,所以很多人也称它为HTTPS证书。
柳絮云泡泡
2023/03/02
1.9K0
怎么选择SSL证书?
电商网站使用哪种证书比较好?
进入新千年以来,网络技术的迅猛发展和快速普及应用,给我们的生活,工作,学习带来了极大的便利。尤其是最近10年的发展,使得我们的生活方式也随之改变,比较典型的就是现代社会对网络购物的极大需求。这也由此推动了电商网站的发展壮大,并且随着网络安全意识的提升,通过网站加密保护用户数据安全,已经成为诸多电商网站的共识。
JoySSL
2023/02/23
5030
电商网站使用哪种证书比较好?
网络安全的最佳解决方案—SSL证书
如今,由于网络已经渗透进我们生活的方方面面,人们对网络的依赖感逐渐增强。在当今脆弱的网络市场中,网络安全问题显得尤为重要。
柳絮云泡泡
2023/02/17
6120
网络安全的最佳解决方案—SSL证书
使用HTTPS协议的常见误区
随着当下企业网络信息安全意识的提升,以及Google等浏览器对使用HTTP协议页面增加风险提示,现在越来越多的网站开始部署安装SSL证书使用HTTPS协议。但对于HTTPS协议的使用,目前并没有全面普及开来,这也导致了部分大众对HTTPS协议产生了误解,只有把这些认识上的误区破除,才能让HTTPS协议发挥最大的效用。
JoySSL
2023/03/14
4650
使用HTTPS协议的常见误区
谁说安装SSL证书会拖慢网站?粉碎这8大常见误区!
现在,全球各大浏览器,常见的谷歌、百度等主流浏览器宣布优先展示使用HTTPS协议的网站之后,越来越多的网站开始安装SSL证书。
做个网站就这么简单
2025/06/30
520
谁说安装SSL证书会拖慢网站?粉碎这8大常见误区!
SSL证书是什么?SSL证书怎么申请?
  SSL证书是数字证书的一种,由权威数字证书机构(CA)验证网站身份后颁发,可实现浏览器和网站服务器数据传输加密。网站安装SSL证书后会在浏览器显示安全锁标志,数据传输协议从http(传统协议) 升级为 https(加密协议)。
安信SSL证书
2019/08/15
10K0
SSL证书是什么?SSL证书怎么申请?
SSL证书是选免费的还是付费的好?
在当今的数字化时代,网络安全已经成为了每个网站和应用程序的重要组成部分。为了保护用户的数据安全,许多网站和应用程序都选择了使用SSL证书。然而,面对市场上的各种SSL证书,用户往往会面临一个问题:SSL证书是选免费的还是付费的好?
稀糊牛肉粥
2023/11/28
1.3K0
小程序怎么申请SSL证书?
微信小程序开发前提必须拥有一本SSL证书,办理SSL证书之前确保好指定的微信小程序开发接口使用的域名,如果没有域名的提前申请好,并且到国内服务器提供商去办理备案。
稀糊牛肉粥
2023/11/09
1.1K0
SSL证书=安全?
众所周知,以“https”开头的网站为访问者提供隐私和安全,毕竟,HTTPS(超文本传输协议)中的“S”代表“Secure”。事实上,我们也鼓励人们在这些安全网站的浏览器地址栏中寻找锁的标识, “https”的存在和锁图标理应表明web流量是加密的,并且访问者可以安全地共享数据。
柳絮云泡泡
2023/03/22
4.4K0
SSL证书=安全?
SSL证书的这些作用你知道吗?
用户通过http协议访问网站时,浏览器和服务器之间是明文传输,这就意味着用户填写的密码、账号、交易记录等机密信息都是明文,随时可能被泄露、窃取、篡改,被黑客加以利用。
柳絮云泡泡
2023/03/20
1.3K0
SSL证书的这些作用你知道吗?
关于 SSL 证书
在 HTTPS 协议大行其道的今天,其通信所需要的 SSL 证书也是不可或缺的一环,如果访问没有 SSL 证书的网站,就是下面这样的:
编程三昧
2022/01/24
4.4K0
关于 SSL 证书
相关推荐
SSL证书价格差异
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • 理论差异
    • Java-WebSocket
    • Netty-WebSocket
  • 被测服务
  • 单链接对比
    • 空Java进程
    • Java-WebSocket
    • Netty-WebSocket
    • 结论
  • 1000连接
    • Netty-WebSocket
    • Java-WebSocket
    • Netty极限
    • 结论
  • 代码更新
    • WebSocketConnector
    • WebSocketIoHandler
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档