websocket,用AI生成的畦幢,估計(jì)都是網(wǎng)上大神的代碼坎吻,整合了一下,做點(diǎn)參考

純javaAPI (只能在控制臺(tái)操作宇葱,沒有界面)

TestServerString

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

public class TestServerString {

    public static void main(String[] args) {

        try{
            //1.創(chuàng)建ServerSocket類型的對(duì)象并提供端口號(hào)
            ServerSocket ss = new ServerSocket(8888);

            //2.等待客戶端的連接請(qǐng)求瘦真,調(diào)用accept()方法
            //實(shí)現(xiàn)服務(wù)器可以不斷地響應(yīng)客戶端的連接請(qǐng)求
            while(true){
                System.out.println("等待客戶端的連接請(qǐng)求...");
                //當(dāng)沒有客戶端連接時(shí),則阻塞在accept()方法的調(diào)用這里
                //只要有客戶端連接成功黍瞧,則阻塞解除
                Socket s = ss.accept();
                System.out.println("客戶端" + s.getInetAddress() + "連接成功诸尽!");
                //每當(dāng)有一個(gè)客戶端連接成功,則開啟一個(gè)新的線程為之服務(wù)
                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.構(gòu)造Socket類型的對(duì)象并提供服務(wù)器的IP地址和端口號(hào)
            //Socket s = new Socket("XDL-20170621QCO", 8888);
            Socket s = new Socket("127.0.0.1", 8888);
            System.out.println("連接服務(wù)器成功印颤!");

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

            while(true){
                //提示用戶從鍵盤輸入要發(fā)送的內(nèi)容然后發(fā)送到服務(wù)器
                System.out.println("請(qǐng)輸入要發(fā)送的內(nèi)容:");
                String msg = sc.nextLine();
                //讓客戶端向服務(wù)器發(fā)送字符串內(nèi)容"hello"
                //ps.println("hello");
                ps.println(msg);
                System.out.println("客戶端發(fā)送數(shù)據(jù)成功您机!");
                //當(dāng)客戶端向服務(wù)器發(fā)送"bye"后,則通信結(jié)束
                if("bye".equalsIgnoreCase(msg)){
                    System.out.println("聊天結(jié)束");
                    break;
                }
                //實(shí)現(xiàn)客戶端接收服務(wù)器發(fā)來(lái)的消息
                String answer = br.readLine();
                System.out.println("服務(wù)器回發(fā)的內(nèi)容是:" + answer);
            }

            //3.關(guān)閉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.使用輸入輸出流進(jìn)行通信
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    s.getInputStream()));
            PrintStream ps = new PrintStream(s.getOutputStream());

            while(true){
                //System.out.println("等待客戶端發(fā)送數(shù)據(jù)內(nèi)容...");
                //接收客戶端發(fā)來(lái)的字符串內(nèi)容并打印出來(lái)
                String str = br.readLine();
                //System.out.println("服務(wù)器接收到的消息是:" + str); //hello
                System.out.println("客戶端" + s.getInetAddress() + "說(shuō):" + str);
                //當(dāng)服務(wù)器接收到客戶端發(fā)來(lái)的“bye”年局,則聊天結(jié)束
                if("bye".equalsIgnoreCase(str)){
                    System.out.println("客戶端" + s.getInetAddress() + "已下線际看!");
                    break;
                }
                //當(dāng)服務(wù)器接收到客戶端發(fā)來(lái)的內(nèi)容向客戶端回發(fā)消息"I received!"
                ps.println("I received!");
                //System.out.println("成功回發(fā)消息!");
            }

            //4.關(guān)閉Socket
            ps.close();
            br.close();
            s.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

vue+原生js WebSocket + javaWebSocket API

1矢否、后端pom.xml導(dǎo)入依賴

 <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("客戶端連接已關(guān)閉");
    }

    @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("發(fā)生錯(cuò)誤");
        ex.printStackTrace();
    }

    public static void main(String[] args) {
        try {
            TestServerWebSocket server = new TestServerWebSocket(8888);
            server.start();
            System.out.println("服務(wù)器啟動(dòng)在端口 8888");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onStart() {
        
    }
}

3、vue + js原生WebSocket

<template>
  <div>
    <h1>WebSocket 實(shí)時(shí)數(shù)據(jù)</h1>
    <ul>
      <input v-model="input">
      <button @click="sendMessage">發(fā)送</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連接已關(guān)閉', event);
    });

    socket.addEventListener('error', (event) => {
      console.error('WebSocket發(fā)生錯(cuò)誤:', 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 注解表示此類是一個(gè) WebSocket 端點(diǎn)
// 通過(guò) 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")) {
            // 由服務(wù)器主動(dòng)關(guān)閉連接屑彻。狀態(tài)碼為 NORMAL_CLOSURE(正常關(guān)閉)。
            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 到對(duì)象
        this.session = session;
        LOGGER.info("[websocket] 新的連接:id={}", this.session.getId());
    }

    // 連接關(guān)閉
    @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());
        
        // 關(guān)閉連接。狀態(tài)碼為 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(); 
        // 手動(dòng)注冊(cè) WebSocket 端點(diǎn)
        exporter.setAnnotatedEndpointClasses(EchoChannel.class); 
        return exporter;
    }  
}

前端vue(純?cè)鷍s websocket)

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

<script setup>
import { ref } from 'vue'
// 用來(lái)接收后端返回?cái)?shù)據(jù)
let getMsg = ref([])
let websocket = new WebSocket("ws://localhost:8080/channel/echo");

// 連接斷開
websocket.onclose = e => {
  console.log(`連接關(guān)閉: code=${e.code}, reason=${e.reason}`)
}
// 收到消息
websocket.onmessage = e => {
  console.log(`收到消息:${e.data}`);
  // 接收后端發(fā)送的消息
  getMsg.value.push(e.data)
}
// 異常
websocket.onerror = e => {
  console.log("連接異常")
  console.error(e)
}

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

  // 創(chuàng)建連接后悴了,往服務(wù)器沒隔一秒連續(xù)寫入1條消息 
  setInterval(sentData, 1000);

  function sentData() {
    websocket.send("hello")
  }
  // 最后發(fā)送 bye膳沽,由服務(wù)器斷開連接
  // websocket.send("bye");

  // 也可以由客戶端主動(dòng)斷開
  // websocket.close();
}

</script>

以上代碼后端是廣播方式發(fā)送消息,想實(shí)現(xiàn)指定客戶端返回?cái)?shù)據(jù)让禀,稍微修改一下以上EchoChannel 代碼

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

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

    private Session session; 
    
    //用來(lái)記錄不同客戶端的sessionID,區(qū)分不同客戶端
    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")) {
            // 由服務(wù)器主動(dòng)關(guān)閉連接。狀態(tài)碼為 NORMAL_CLOSURE(正常關(guān)閉)巡揍。
            this.session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Bye")); 
            return;
        }
        System.out.println(clientId);
        if (clientId.equals("[10]")) {
            sendMessageToClient(clientId, "你是" + clientId + "號(hào)客戶端");
        }
        if (clientId.equals("[20]")) {
            sendMessageToClient(clientId, "你好" + clientId + "號(hào)客戶端");
        }
    }

    // 獲取客戶端id痛阻,用來(lái)識(shí)別是哪個(gè)客戶端發(fā)送的消息
    private static String getClientIdFromSession(Session session) {
        String query = session.getRequestParameterMap().get("clientId").toString();
        return query != null ? query : "";
    }
    
    // 發(fā)送消息的邏輯
    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] 發(fā)送給指定客戶端:clientId={}, message={}", clientId, message);
            } catch (Exception e) {
                LOGGER.error("[websocket] 發(fā)送消息異常:clientId={}, message={}, error={}", clientId, message, e.getMessage());
                // 處理異常情況,可能需要移除無(wú)法通信的Session
            }
        } else {
            LOGGER.warn("[websocket] 嘗試發(fā)送消息到不存在或已關(guān)閉的連接:clientId={}", clientId);
        }
    }
    
    // 連接打開
    @OnOpen
    public void onOpen(Session session, EndpointConfig endpointConfig){
         // 假設(shè)這里你有方法獲取客戶端的唯一標(biāo)識(shí)腮敌,比如從session的屬性中獲取
        String clientId = getClientIdFromSession(session); // 實(shí)現(xiàn)這個(gè)方法來(lái)獲取客戶端ID 
        // 保存 session 到對(duì)象
        this.session = session;
        SESSION_MAP.put(clientId, session);
        LOGGER.info("[websocket] 新的連接:id={}, clientId={}", session.getId(), clientId);
    }

    // 連接關(guān)閉
    @OnClose
    public void onClose(CloseReason closeReason){
        String clientId = getClientIdFromSession(this.session); // 同樣阱当,確保實(shí)現(xiàn)這個(gè)方法
        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());
        
        // 關(guān)閉連接弊添。狀態(tài)碼為 UNEXPECTED_CONDITION(意料之外的異常)
        this.session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, throwable.getMessage()));
    }
}

客戶端連接服務(wù)端的路徑需要加上參數(shù)clientId

"ws://localhost:8080/channel/echo?clientId=" + 10
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市捌木,隨后出現(xiàn)的幾起案子油坝,更是在濱河造成了極大的恐慌,老刑警劉巖刨裆,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澈圈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡帆啃,警方通過(guò)查閱死者的電腦和手機(jī)瞬女,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)努潘,“玉大人诽偷,你說(shuō)我怎么就攤上這事》枥ぃ” “怎么了报慕?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)贴膘。 經(jīng)常有香客問(wèn)我卖子,道長(zhǎng),這世上最難降的妖魔是什么刑峡? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任洋闽,我火速辦了婚禮,結(jié)果婚禮上突梦,老公的妹妹穿的比我還像新娘诫舅。我一直安慰自己,他們只是感情好宫患,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布刊懈。 她就那樣靜靜地躺著,像睡著了一般娃闲。 火紅的嫁衣襯著肌膚如雪虚汛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天皇帮,我揣著相機(jī)與錄音卷哩,去河邊找鬼。 笑死属拾,一個(gè)胖子當(dāng)著我的面吹牛将谊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播渐白,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼尊浓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了纯衍?” 一聲冷哼從身側(cè)響起栋齿,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎襟诸,沒想到半個(gè)月后褒颈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡励堡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年谷丸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片应结。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡刨疼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鹅龄,到底是詐尸還是另有隱情揩慕,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布扮休,位于F島的核電站迎卤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏玷坠。R本人自食惡果不足惜蜗搔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一劲藐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧樟凄,春花似錦聘芜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至叔壤,卻和暖如春瞎饲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背炼绘。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工嗅战, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饭望。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓仗哨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親铅辞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厌漂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,867評(píng)論 6 342
  • 1 頁(yè)面發(fā)布 1.1 技術(shù)方案 技術(shù)方案說(shuō)明: 1、平臺(tái)包括多個(gè)站點(diǎn)斟珊,頁(yè)面歸屬不同的站點(diǎn)苇倡。 2、發(fā)布一個(gè)頁(yè)面應(yīng)將該...
    lww文閱讀 442評(píng)論 0 0
  • 1.說(shuō)說(shuō)你對(duì)盒子模型的理解 當(dāng)對(duì)一個(gè)文檔進(jìn)行布局(layout)的時(shí)候囤踩,瀏覽器的渲染引擎會(huì)根據(jù)標(biāo)準(zhǔn)之一的 CSS ...
    Ysrenacer1_bcfd閱讀 2,125評(píng)論 0 19
  • 1 整合阿里云OSS 01-阿里云存儲(chǔ)OSS 一旨椒、對(duì)象存儲(chǔ)OSS 為了解決海量數(shù)據(jù)存儲(chǔ)與彈性擴(kuò)容,項(xiàng)目中我們采用云...
    刊ing閱讀 1,889評(píng)論 0 0
  • 前端技術(shù)淺談 1堵漱、前端框架發(fā)展 以銅為鑒综慎,可以正衣冠;以人為鑒勤庐,可以明得失示惊;以史為鑒,可以知興替愉镰。 本文主題:前端...
    BeautifulHao閱讀 1,253評(píng)論 1 5