guzhizang 2024-04-11 16:09 采纳率: 71.4%
浏览 23
已结题

org.java-websocket 服务端有客户端连接时,重启服务器端 时websocket 无法启动

org.java-websocket 服务端有客户端连接时,重启服务器端 时websocket 无法启动
相关代码
 <dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.5.0</version>
        </dependency>

WebSocketService
 public class WebSocketService {
    private  WebSocket  webSocket;
    private Jedis jedis;
    private static Logger log = Logger.getLogger(StartWebSocket.class);

    public void startWebSocket() {
        try {
             webSocket = new WebSocket("192.168.55.144", 8888);
            //订阅redis消息 开启线程防止阻塞
            final RedisSubscriber redisPubSub = new RedisSubscriber();
            final JedisDao jedisDao = (JedisDao) Component.getInstance("jedisDao");
            jedis = jedisDao.getJedis();
            new Thread(new Runnable() {
                public void run() {
                    try {
                        redisPubSub.subscribe("webSocket", jedis, WebSocketService.this);
                    } catch (Exception e) {
                        log.error("Redis Subscribing failed.", e);
                    }
                }
            }).start();
            webSocket.start();
        } catch (Exception e) {
            log.error(e);
            throw new BusinessException(e);
        }
    }


}

WebSocket
public class WebSocket extends WebSocketServer {
    private static JedisDao jedisDao;
    /**
     * 保存用户连接和用户id
     */
    private static final String urlPrefix = "webSocket";
    //单账号多次登录
    private static final Map<String, List<WebSocket>> users = new ConcurrentHashMap<>();


    public WebSocket(String url, int port) {
        super(new InetSocketAddress(url, port));
    }
    /**
     * 关闭链接则删除用户
     *
     * @param conn
     * @param code
     * @param reason
     * @param remote
     */
    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
         
    }

    @Override
    public void onError(WebSocket conn, Exception ex) {
        ex.printStackTrace();
    }

    @Override
    public void onStart() {
        System.out.println("******************webSocket启动成功*****************");
    }

    /**
     * 处理客户端的消息
     *
     * @param conn
     * @param message
     */
    @Override
    public void onMessage(WebSocket conn, String message) {
        // 不需要接收客户端消息
        //sendMsgToOne(conn, message);
    }

    /**
     * onOpen():有客户端连接回调,回调参数中有连接WebSocket可用于发送消息,可保存通道用于发送数据
     *
     * @param conn
     * @param handshake
     */
    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
        String[] url = handshake.getResourceDescriptor().split("/");
        //前缀校验
        if (!url[1].equals(urlPrefix)) {
            return;
        }
        List<WebSocket> webSockets = users.get(url[2]);
        if (CollectionUtils.isEmpty(webSockets)) {
            webSockets = new ArrayList<>();
        }
   
        webSockets.add(conn);
        users.put(url[2], webSockets);
    }



}
当有客户端连接时 重启服务端报错
 ERROR (org.java_websocket.server.WebSocketServer:648) - Shutdown due to fatal error
java.net.BindException: Address already in use
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:433)
    at sun.nio.ch.Net.bind(Net.java:425)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at org.java_websocket.server.WebSocketServer.doSetupSelectorAndServerThread(WebSocketServer.java:533)
    at org.java_websocket.server.WebSocketServer.run(WebSocketServer.java:341)
    at java.lang.Thread.run(Thread.java:745)
java.net.BindException: Address already in use
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:433)
    at sun.nio.ch.Net.bind(Net.java:425)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at org.java_websocket.server.WebSocketServer.doSetupSelectorAndServerThread(WebSocketServer.java:533)
    at org.java_websocket.server.WebSocketServer.run(WebSocketServer.java:341)
    at java.lang.Thread.run(Thread.java:745)

当没有客户端连接时 重启服务端 WebSocketServer可以正常启动

  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-11 16:09
    关注

    引自免费微信小程序:皆我百晓生

    看起来你在运行 WebSocket 服务时遇到了一些问题。在 Java 中,Address already in use 错误通常表示你试图绑定到一个已经被另一个进程使用的网络端口上。在这种情况下,由于 WebSocketServer 在尝试重新启动时仍然试图使用相同的端口(8888),所以出现了这个错误。

    为了解决这个问题,你可以采取以下步骤:

    1. 确保每次服务器重启时,WebSocketServer 使用不同的端口。这可以通过在启动时动态分配端口来实现。
    2. 或者,在服务器关闭之前,确保正确地停止了 WebSocketServer,并释放了端口资源。

    这里是一个修改后的 WebSocketService 类,它会动态选择一个未被占用的端口:

    import org.java_websocket.WebSocket;
    import org.java_websocket.handshake.ClientHandshake;
    import org.java_websocket.server.WebSocketServer;
    
    import java.io.IOException;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class WebSocketService {
    
        private static AtomicInteger portCounter = new AtomicInteger(8888); // 初始化端口从8888开始
    
        public void startWebSocket() {
            try {
                // 动态获取下一个可用端口
                int nextPort = findAvailablePort(portCounter.incrementAndGet());
                
                WebSocket webSocket = new WebSocket("192.168.55.144", nextPort);
                
                // ...其他初始化逻辑...
    
                webSocket.start();
            } catch (IOException e) {
                log.error("Error starting WebSocket server", e);
                throw new BusinessException(e);
            }
        }
    
        private int findAvailablePort(int port) throws IOException {
            ServerSocket socket = null;
            try {
                socket = new ServerSocket(port);
                return port;
            } finally {
                if (socket != null) {
                    socket.close();
                }
            }
        }
    }
    

    这段代码首先定义了一个原子整数 portCounter,用于跟踪下次要尝试的端口号。然后,在 startWebSocket() 方法中,我们调用 findAvailablePort() 函数来查找并返回下一个可用的端口。如果找到了可用的端口,就创建一个新的 WebSocket 并启动它。

    注意,这个解决方案可能会导致在某些极端情况下,找不到可用的端口。为了提高可靠性,你可能还需要添加重试机制,或者设置一个最大端口范围,以及在端口范围内寻找空闲端口。

    此外,如果你的服务器在重启时没有正确关闭 WebSocketServer,你需要检查你的应用程序关闭逻辑,确保在关闭服务器时执行了正确的清理操作,例如调用 webSocket.stop()

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 4月20日
  • 已采纳回答 4月12日
  • 创建了问题 4月11日

悬赏问题

  • ¥15 气象网格数据与卫星轨道数据如何匹配
  • ¥100 java ee ssm项目 悬赏,感兴趣直接联系我
  • ¥15 微软账户问题不小心注销了好像
  • ¥15 x264库中预测模式字IPM、运动向量差MVD、量化后的DCT系数的位置
  • ¥15 curl 命令调用正常,程序调用报 java.net.ConnectException: connection refused
  • ¥20 关于web前端如何播放二次加密m3u8视频的问题
  • ¥15 使用百度地图api 位置函数报错?
  • ¥15 metamask如何添加TRON自定义网络
  • ¥66 关于川崎机器人调速问题
  • ¥15 winFrom界面无法打开