美文网首页
websocket,用AI生成的,估计都是网上大神的代码,整合了

websocket,用AI生成的,估计都是网上大神的代码,整合了

作者: 晓晓_1931 | 来源:发表于2024-06-24 13:02 被阅读0次

纯javaAPI (只能在控制台操作,没有界面)

TestServerString

import java.net.ServerSocket;
import java.net.Socket;

public class TestServerString {

    public static void main(String[] args) {

        try{
            //1.创建ServerSocket类型的对象并提供端口号
            ServerSocket ss = new ServerSocket(8888);

            //2.等待客户端的连接请求,调用accept()方法
            //实现服务器可以不断地响应客户端的连接请求
            while(true){
                System.out.println("等待客户端的连接请求...");
                //当没有客户端连接时,则阻塞在accept()方法的调用这里
                //只要有客户端连接成功,则阻塞解除
                Socket s = ss.accept();
                System.out.println("客户端" + s.getInetAddress() + "连接成功!");
                //每当有一个客户端连接成功,则开启一个新的线程为之服务
                new ServerThread(s).start();
            }
            //ss.close();
        }catch(Exception e){
            e.printStackTrace();
        } 
    } 
}

TestClientString

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class TestClientString {

    public static void main(String[] args) {

        try{
            //1.构造Socket类型的对象并提供服务器的IP地址和端口号
            //Socket s = new Socket("XDL-20170621QCO", 8888);
            Socket s = new Socket("127.0.0.1", 8888);
            System.out.println("连接服务器成功!");

            //2.使用输入输出流进行通信
            Scanner sc = new Scanner(System.in);
            PrintStream ps = new PrintStream(s.getOutputStream());
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    s.getInputStream()));

            while(true){
                //提示用户从键盘输入要发送的内容然后发送到服务器
                System.out.println("请输入要发送的内容:");
                String msg = sc.nextLine();
                //让客户端向服务器发送字符串内容"hello"
                //ps.println("hello");
                ps.println(msg);
                System.out.println("客户端发送数据成功!");
                //当客户端向服务器发送"bye"后,则通信结束
                if("bye".equalsIgnoreCase(msg)){
                    System.out.println("聊天结束");
                    break;
                }
                //实现客户端接收服务器发来的消息
                String answer = br.readLine();
                System.out.println("服务器回发的内容是:" + answer);
            }

            //3.关闭Socket
            br.close();
            ps.close();
            sc.close();
            s.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

}

ServerThread

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

public class ServerThread extends Thread {
    private Socket s;

    public ServerThread(Socket s){
        this.s = s;
    }

    @Override
    public void run(){
        try{
            //3.使用输入输出流进行通信
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    s.getInputStream()));
            PrintStream ps = new PrintStream(s.getOutputStream());

            while(true){
                //System.out.println("等待客户端发送数据内容...");
                //接收客户端发来的字符串内容并打印出来
                String str = br.readLine();
                //System.out.println("服务器接收到的消息是:" + str); //hello
                System.out.println("客户端" + s.getInetAddress() + "说:" + str);
                //当服务器接收到客户端发来的“bye”,则聊天结束
                if("bye".equalsIgnoreCase(str)){
                    System.out.println("客户端" + s.getInetAddress() + "已下线!");
                    break;
                }
                //当服务器接收到客户端发来的内容向客户端回发消息"I received!"
                ps.println("I received!");
                //System.out.println("成功回发消息!");
            }

            //4.关闭Socket
            ps.close();
            br.close();
            s.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

vue+原生js WebSocket + javaWebSocket API

1、后端pom.xml导入依赖

 <dependencies>
      <dependency>
        <groupId>org.java-websocket</groupId>
        <artifactId>Java-WebSocket</artifactId>
        <version>1.5.2</version>
      </dependency>
  </dependencies>

2、后端TestServerWebSocket类

import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;

public class TestServerWebSocket extends WebSocketServer {

    public TestServerWebSocket(int port) {
        super(new InetSocketAddress(port));
    }

    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
        System.out.println("客户端连接已打开");
    }

    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
        System.out.println("客户端连接已关闭");
    }

    @Override
    public void onMessage(WebSocket conn, String message) {
        System.out.println("从客户端接收到消息: " + message);
        // 向所有连接的客户端广播消息
        broadcast("hello");
    }

    @Override
    public void onError(WebSocket conn, Exception ex) {
        System.out.println("发生错误");
        ex.printStackTrace();
    }

    public static void main(String[] args) {
        try {
            TestServerWebSocket server = new TestServerWebSocket(8888);
            server.start();
            System.out.println("服务器启动在端口 8888");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onStart() {
        
    }
}

3、vue + js原生WebSocket

<template>
  <div>
    <h1>WebSocket 实时数据</h1>
    <ul>
      <input v-model="input">
      <button @click="sendMessage">发送</button>
      <p>{{ message }}</p>
    </ul>
  </div>
</template>

<script setup>
    import { ref } from 'vue'
    const socket = new WebSocket('ws://localhost:8888');

    socket.addEventListener('open', (event) => {
      console.log('WebSocket连接已打开', event);
    });

    socket.addEventListener('close', (event) => {
      console.log('WebSocket连接已关闭', event);
    });

    socket.addEventListener('error', (event) => {
      console.error('WebSocket发生错误:', event);
    });

    let message = ref('')
    socket.addEventListener('message', (event) => {
      // message = JSON.parse(event.data);
      message.value = event.data;
      console.log(message)
    });

    let input = ref('')
    function sendMessage() {
      socket.send(input.value);
      input.value = '';
    }
</script>

springboot+websocket

依赖 pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

EchoChannel.java

import java.io.IOException;
import java.time.Instant;

import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// 使用 @ServerEndpoint 注解表示此类是一个 WebSocket 端点
// 通过 value 注解,指定 websocket 的路径
@ServerEndpoint(value = "/channel/echo")
public class EchoChannel {

    private static final Logger LOGGER = LoggerFactory.getLogger(EchoChannel.class);

    private Session session;

    // 收到消息
    @OnMessage
    public void onMessage(String message) throws IOException{
        
        LOGGER.info("[websocket] 收到消息:id={},message={}", this.session.getId(), message);
        
        if (message.equalsIgnoreCase("bye")) {
            // 由服务器主动关闭连接。状态码为 NORMAL_CLOSURE(正常关闭)。
            this.session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Bye"));;
            return;
        }
        
        
        this.session.getAsyncRemote().sendText("["+ Instant.now().toEpochMilli() +"]" + new Random().nextInt());
    }

    // 连接打开
    @OnOpen
    public void onOpen(Session session, EndpointConfig endpointConfig){
        // 保存 session 到对象
        this.session = session;
        LOGGER.info("[websocket] 新的连接:id={}", this.session.getId());
    }

    // 连接关闭
    @OnClose
    public void onClose(CloseReason closeReason){
        LOGGER.info("[websocket] 连接断开:id={},reason={}", this.session.getId(),closeReason);
    }

    // 连接异常
    @OnError
    public void onError(Throwable throwable) throws IOException {
        
        LOGGER.info("[websocket] 连接异常:id={},throwable={}", this.session.getId(), throwable.getMessage());
        
        // 关闭连接。状态码为 UNEXPECTED_CONDITION(意料之外的异常)
        this.session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, throwable.getMessage()));
    }
}

WebSocketConfiguration.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
  
@Configuration
public class WebSocketConfiguration { 
    @Bean  
    public ServerEndpointExporter serverEndpointExporter(){ 
        ServerEndpointExporter exporter = new ServerEndpointExporter(); 
        // 手动注册 WebSocket 端点
        exporter.setAnnotatedEndpointClasses(EchoChannel.class); 
        return exporter;
    }  
}

前端vue(纯原生js websocket)

<template>
  <div>
    <h1>WebSocket 实时通信</h1>
    <ul>
      <li v-for="(msg, index) in getMsg" :key="index">{{ msg }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue'
// 用来接收后端返回数据
let getMsg = ref([])
let websocket = new WebSocket("ws://localhost:8080/channel/echo");

// 连接断开
websocket.onclose = e => {
  console.log(`连接关闭: code=${e.code}, reason=${e.reason}`)
}
// 收到消息
websocket.onmessage = e => {
  console.log(`收到消息:${e.data}`);
  // 接收后端发送的消息
  getMsg.value.push(e.data)
}
// 异常
websocket.onerror = e => {
  console.log("连接异常")
  console.error(e)
}

// 连接打开
websocket.onopen = e => {
  console.log("连接打开", e);

  // 创建连接后,往服务器没隔一秒连续写入1条消息 
  setInterval(sentData, 1000);

  function sentData() {
    websocket.send("hello")
  }
  // 最后发送 bye,由服务器断开连接
  // websocket.send("bye");

  // 也可以由客户端主动断开
  // websocket.close();
}

</script>

以上代码后端是广播方式发送消息,想实现指定客户端返回数据,稍微修改一下以上EchoChannel 代码

@ServerEndpoint(value = "/channel/echo")
public class EchoChannel {

    private static final Logger LOGGER = LoggerFactory.getLogger(EchoChannel.class);

    private Session session; 
    
    //用来记录不同客户端的sessionID,区分不同客户端
    private static final Map<String, Session> SESSION_MAP = new ConcurrentHashMap<>();


    // 收到消息
    @OnMessage
    public void onMessage(String message) throws IOException{
        String clientId = getClientIdFromSession(session);
        LOGGER.info("[websocket] 收到消息:clientId={},message={}", clientId, message);
        
        if (message.equalsIgnoreCase("bye")) {
            // 由服务器主动关闭连接。状态码为 NORMAL_CLOSURE(正常关闭)。
            this.session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Bye")); 
            return;
        }
        System.out.println(clientId);
        if (clientId.equals("[10]")) {
            sendMessageToClient(clientId, "你是" + clientId + "号客户端");
        }
        if (clientId.equals("[20]")) {
            sendMessageToClient(clientId, "你好" + clientId + "号客户端");
        }
    }

    // 获取客户端id,用来识别是哪个客户端发送的消息
    private static String getClientIdFromSession(Session session) {
        String query = session.getRequestParameterMap().get("clientId").toString();
        return query != null ? query : "";
    }
    
    // 发送消息的逻辑
    public static void sendMessageToClient(String clientId, String message) {
        Session session = SESSION_MAP.get(clientId);
        if (session != null && session.isOpen()) {
            try {
                session.getAsyncRemote().sendText(message);
                LOGGER.info("[websocket] 发送给指定客户端:clientId={}, message={}", clientId, message);
            } catch (Exception e) {
                LOGGER.error("[websocket] 发送消息异常:clientId={}, message={}, error={}", clientId, message, e.getMessage());
                // 处理异常情况,可能需要移除无法通信的Session
            }
        } else {
            LOGGER.warn("[websocket] 尝试发送消息到不存在或已关闭的连接:clientId={}", clientId);
        }
    }
    
    // 连接打开
    @OnOpen
    public void onOpen(Session session, EndpointConfig endpointConfig){
         // 假设这里你有方法获取客户端的唯一标识,比如从session的属性中获取
        String clientId = getClientIdFromSession(session); // 实现这个方法来获取客户端ID 
        // 保存 session 到对象
        this.session = session;
        SESSION_MAP.put(clientId, session);
        LOGGER.info("[websocket] 新的连接:id={}, clientId={}", session.getId(), clientId);
    }

    // 连接关闭
    @OnClose
    public void onClose(CloseReason closeReason){
        String clientId = getClientIdFromSession(this.session); // 同样,确保实现这个方法
        SESSION_MAP.remove(clientId);
        LOGGER.info("[websocket] 连接断开:id={},reason={}, clientId={}", this.session.getId(), closeReason, clientId);
         
    }

    // 连接异常
    @OnError
    public void onError(Throwable throwable) throws IOException {
        
        LOGGER.info("[websocket] 连接异常:id={},throwable={}", this.session.getId(), throwable.getMessage());
        
        // 关闭连接。状态码为 UNEXPECTED_CONDITION(意料之外的异常)
        this.session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, throwable.getMessage()));
    }
}

客户端连接服务端的路径需要加上参数clientId

"ws://localhost:8080/channel/echo?clientId=" + 10

相关文章

网友评论

      本文标题:websocket,用AI生成的,估计都是网上大神的代码,整合了

      本文链接:https://www.haomeiwen.com/subject/sdxdcjtx.html