云计算百科
云计算领域专业知识百科平台

服务器中使用wss协议连接websocket(基于netty)

前置条件:可用的SSL证书

需要两个文件,key格式的还有pem格式的

如果是阿里云证书,下面Nginx类型的就可以

快捷转移——数字证书管理服务管理控制台 (aliyun.com)

在这里插入图片描述

自建证书

以管理员形式打开cmd窗口,如果提示keytool不存在,将目录定位到java安装目录的bin下方。

1、生成证书

keytool -genkey -alias myalias -keyalg RSA -keysize 2048 -keystore mykeystore.jks -validity 365

2、jks证书转化为pem格式

keytool -export -alias myalias -keystore mykeystore.jks -rfc -file certificate.pem

3、导出私钥

keytool -importkeystore -srckeystore mykeystore.jks -destkeystore temp.p12 -srcalias myalias -deststoretype PKCS12 -srcstorepass <keystore_password> -deststorepass <p12_password>

4、提取私钥

openssl pkcs12 -in temp.p12 -nocerts -nodes -out private_key.pem

这种方式得到两个接下来要用到的文件

① certificate.pem

② private_key.pem

阿里云证书的方式直接下载得到的是key和pem,需要将key转化为私钥

执行openssl rsa -in old_server_key.pem -out private_key.pem

这样也得到了上述两个文件

接下来使用netty搭建简易websocket服务器

@Configuration
@Slf4j
public class NettyWebSocketServer {

private final static int WEB_SOCKET_PORT = 9090;

private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
private final EventLoopGroup workerGroup = new NioEventLoopGroup(NettyRuntime.availableProcessors());

@PostConstruct
public void start() throws Exception {
run();
}

@PreDestroy
public void destroy() {
Future<?> future = bossGroup.shutdownGracefully();
Future<?> future1 = workerGroup.shutdownGracefully();
future.syncUninterruptibly();
future1.syncUninterruptibly();
log.info("关闭 ws server 成功");
}

public void run() throws Exception {
ServerBootstrap serverBootstrap = new ServerBootstrap();
SslContext sslContext = SslContextBuilder.forServer(getCertPem(), getCertKey()).build();

serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new LoggingHandler(LogLevel.INFO)) // 为 bossGroup 添加 日志处理器
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 注意将SSL必须是第一个处理器
pipeline.addLast(sslContext.newHandler(socketChannel.alloc()));

//30秒客户端没有向服务器发送心跳则关闭连接
pipeline.addLast(new IdleStateHandler(30, 0, 0));
// 因为使用http协议,所以需要使用http的编码器,解码器
pipeline.addLast(new HttpServerCodec());
// 以块方式写,添加 chunkedWriter 处理器
pipeline.addLast(new ChunkedWriteHandler());
/**
* 说明:
* 1. http数据在传输过程中是分段的,HttpObjectAggregator可以把多个段聚合起来;
* 2. 这就是为什么当浏览器发送大量数据时,就会发出多次 http请求的原因
*/

pipeline.addLast(new HttpObjectAggregator(8192));
//保存用户ip
pipeline.addLast(new HttpHeadersHandler());
/**
*
*/

pipeline.addLast(new WebSocketServerProtocolHandler("/"));
}
});
// 启动服务器,监听端口,阻塞直到启动成功
serverBootstrap.bind(WEB_SOCKET_PORT).sync();
log.info("netty在{}启动成功", WEB_SOCKET_PORT);
}

private InputStream getCertPem() {
ClassPathResource classPathResource = new ClassPathResource("certificate.pem");
return classPathResource.getStream();
}

private InputStream getCertKey() {
ClassPathResource classPathResource = new ClassPathResource("private_key.pem");
return classPathResource.getStream();
}

}

然后加成jar包放到服务器上启动。

配置nginx反向代理

server{
listen 443 ssl;
server_name yourservername; # 填写①
ssl_certificate certificate.pem; # 填写路径②
ssl_certificate_key private_key.pem; # 填好路径③
ssl_session_timeout 5m;
root /www/wwwroot; # 自行配置
charset utf8;

location /netty{
proxy_pass https://your-address-url:9090/; # 填写④ 不能是9090 必须是9090/
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
rewrite "^/netty/(.*)$" /$1 break;
}
}

测试 wss://your-server-name/netty 可以连接成功

常见错误

1、io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record

错误说明没有使用SSL/TLS

导致的原因可能是:

① 使用了ws协议连接

② nginx转发的时候使用了http,需要使用https

2、wss Received fatal alert: certificate_unknown

错误说明证书未知

导致的原因可能是:

① 证书错误、不被信任

赞(0)
未经允许不得转载:网硕互联帮助中心 » 服务器中使用wss协议连接websocket(基于netty)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!