WebSocket案例(二) 服务端

  文章目录

前言

WebSocket服务器的功能实现

1. 导入依赖

2. 编写WebSocket的配置类       

3. 自定义WebSocket的服务类

3.1 创建服务类

3.2 定义服务类中对应的事件方法

3.3 服务类的完整代码

总结


前言

         本文将在Spring boot框架下,创建一个web项目来实现WebSocket服务器的功能。

WebSocket服务器的功能实现

1. 导入依赖

         项目是基于spring boot框架构建的,导入其中的WebSocket自动装配依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.7.3</version>
        </dependency>

2. 编写WebSocket的配置类       

        在创建WebSocket服务类之前,需要为其编写一个配置类,配置类中使用@Bean注解将ServerEndpointExporter 对象,也就是服务端点导出器对象交给IOC容器管理,这又这样,spring boot web工程才能识别WebSocket服务类。

package com.example.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket配置类,用于注册WebSocket的Bean
 */
@Configuration
public class WebSocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

3. 自定义WebSocket的服务类

3.1 创建服务类

        创建服务类只需要打上两个注解。

        注解一:@Component 表示该类是IOC容器的组件,将该类交给IOC容器管理。

        注解二:@ServerEndpoint 表示该类是WebSocket的服务类,参数为访问时的映射地址。

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/webSocketServer")
public class WebSocketServer { 

}

3.2 定义服务类中对应的事件方法

        WebSocket中有4个事件分别是open、message、error、close,他们也对应着4个注解。

3.2.1 @OnOpen

        表示连接成功时使用的方法。可以在方法参数上接收一个会话对象,让每一个建立连接的客户端都保存起来,方便后期往客户端发送数据。

    //存放会话对象
    private static List<Session> sessionList = new ArrayList<>();

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("客户端建立连接");
        sessionList.add(session);
    }

3.2.2 @OnMessage

        收到客户端发来消息时执行的方法。这里自定义了一个群发消息的方法,用于个所有连接的客户端发送消息。通过之前保存的会话对象的getBasicRemote()方法来获取一个远程服务端点对象,然后使用这个对象的sendText方法发送一个字符串对象个客户端。

        通过使用getBasicRemote()获取的对象来发送信息,最主要的原因是其特点是阻塞式发送信息。

        还可以使用getAsyncRemote()获取对象来发送信息,其特点是异步式发送。


    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message) {
        System.out.println("收到来自客户端的信息:" + message);
        sendToAllClient(message);
    }

    /**
     * 群发
     *
     * @param message 需要发送的信息
     */
    public void sendToAllClient(String message) {
        for (Session session : sessionList) {
            try {
                //服务器向客户端发送消息
                //getBasicRemote()方法是获取一个远程服务端点对象,通过该对象进行阻塞式的信息传输
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

3.2.3 @OnError

        连接出错时调用的方法

    @OnError
    public void OnError() {
        System.out.println("连接出错");
    }

3.2.3 @OnClose

        连接关闭时调用的方法

    @OnError
    public void OnError() {
        System.out.println("连接出错");
    }

3.3 服务类的完整代码

package com.example.websocket;

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/webSocketServer")
public class WebSocketServer {

    //存放会话对象
    private static List<Session> sessionList = new ArrayList<>();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("客户端建立连接");
        sessionList.add(session);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message) {
        System.out.println("收到来自客户端的信息:" + message);
        sendToAllClient(message);
    }

    /**
     * 群发
     *
     * @param message 需要发送的信息
     */
    public void sendToAllClient(String message) {
        for (Session session : sessionList) {
            try {
                //服务器向客户端发送消息
                //getBasicRemote()方法是获取一个远程服务端点对象,通过该对象进行阻塞式的信息传输
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        System.out.println("连接断开");
    }

    /**
     * 连接出错调用的方法
     */
    @OnError
    public void OnError() {
        System.out.println("连接出错");
    }

}

总结

        WebSocket服务端的实现已经完成,文中的服务端可以结合 WebSocket案例(一) 客户端_C.J.Y的博客-CSDN博客 中的客户端进行测试,只需要将编写客户端的html文件加入到项目中的src/main/resources/statis目录下(如下图),然后启动项目,访问localhost:8080/文件名.html 即可进行页面测试。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Netty实现WebSocket协议的服务端和客户端案例服务端代码: ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; public class WebSocketServer { private final int port; public WebSocketServer(int port) { this.port = port; } public void start() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap() .group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new HttpObjectAggregator(65536)); pipeline.addLast(new WebSocketServerProtocolHandler("/websocket")); pipeline.addLast(new WebSocketServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture future = bootstrap.bind(port).sync(); System.out.println("WebSocket Server started on port " + port); future.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new WebSocketServer(8080).start(); } } ``` 客户端代码: ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; 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.*; import io.netty.handler.codec.http.websocketx.*; import io.netty.util.CharsetUtil; import java.net.URI; public class WebSocketClient { private final URI uri; private final WebSocketClientHandler handler = new WebSocketClientHandler(); private Channel channel; public WebSocketClient(URI uri) { this.uri = uri; } public void start() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap() .group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpClientCodec()); pipeline.addLast(new HttpObjectAggregator(8192)); pipeline.addLast(new WebSocketClientProtocolHandler(uri, WebSocketVersion.V13, null, true, HttpHeaders.EMPTY_HEADERS, 65536)); pipeline.addLast(handler); } }); channel = bootstrap.connect(uri.getHost(), uri.getPort()).sync().channel(); handler.handshakeFuture().sync(); System.out.println("WebSocket Client connected to " + uri); } catch (Exception e) { group.shutdownGracefully(); } } public void stop() { channel.writeAndFlush(new CloseWebSocketFrame()); try { channel.closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } } public void sendMessage(String message) { channel.writeAndFlush(new TextWebSocketFrame(message)); } public static void main(String[] args) throws Exception { WebSocketClient client = new WebSocketClient(new URI("ws://localhost:8080/websocket")); client.start(); client.sendMessage("Hello, Netty WebSocket!"); Thread.sleep(1000); client.stop(); } private static class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> { private final WebSocketClientHandshaker handshaker; private ChannelPromise handshakeFuture; public WebSocketClientHandler() { URI uri = URI.create("ws://localhost:8080/websocket"); handshaker = WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, true, HttpHeaders.EMPTY_HEADERS, 65536); } public ChannelFuture handshakeFuture() { return handshakeFuture; } @Override public void handlerAdded(ChannelHandlerContext ctx) { handshakeFuture = ctx.newPromise(); } @Override public void channelActive(ChannelHandlerContext ctx) { handshaker.handshake(ctx.channel()); } @Override public void channelInactive(ChannelHandlerContext ctx) { System.out.println("WebSocket Client disconnected!"); } @Override public void channelRead0(ChannelHandlerContext ctx, Object msg) { Channel ch = ctx.channel(); if (!handshaker.isHandshakeComplete()) { handshaker.finishHandshake(ch, (FullHttpResponse) msg); System.out.println("WebSocket Client connected!"); handshakeFuture.setSuccess(); return; } if (msg instanceof FullHttpResponse) { FullHttpResponse response = (FullHttpResponse) msg; throw new IllegalStateException( "Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')'); } WebSocketFrame frame = (WebSocketFrame) msg; if (frame instanceof TextWebSocketFrame) { TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; System.out.println("WebSocket Client received message: " + textFrame.text()); } else if (frame instanceof PongWebSocketFrame) { System.out.println("WebSocket Client received pong"); } else if (frame instanceof CloseWebSocketFrame) { System.out.println("WebSocket Client received closing"); ch.close(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); if (!handshakeFuture.isDone()) { handshakeFuture.setFailure(cause); } ctx.close(); } } } ``` 使用时,先启动服务端,再启动客户端。客户端启动后,会向服务端发送一条消息,并在接收到服务端的响应后关闭连接。在控制台上可以看到客户端和服务端的交互过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值