Java通過Socket實(shí)現(xiàn)簡單多人聊天室
本文實(shí)例為大家分享了Java通過Socket實(shí)現(xiàn)多人聊天室的具體代碼,供大家參考,具體內(nèi)容如下
Socket可以實(shí)現(xiàn)網(wǎng)絡(luò)上兩個(gè)程序通過雙向通道進(jìn)行數(shù)據(jù)的交換,此外它是Java中網(wǎng)絡(luò)TCP/IP協(xié)議的封裝,例如可以進(jìn)行網(wǎng)絡(luò)通信等等,下面我們就來簡單寫一下多人聊天室。
首先來分析一下要實(shí)現(xiàn)的流程
- 首先建立一個(gè)服務(wù)器端,構(gòu)建ServerSocket并綁定端口
- 創(chuàng)建socket客戶端,連接到指定ip以及其端口
- 然后使用accept阻塞接收socket發(fā)出的連接請求
- 獲取連接后的socket客戶端的輸入流和輸出流
- 根據(jù)輸入流和輸出流進(jìn)行兩者數(shù)據(jù)的通信
值得一提是:該Socket是同步阻塞的,因此在socket客戶端需要進(jìn)行創(chuàng)建一個(gè)線程,來分別進(jìn)行向服務(wù)器輸出,和接收服務(wù)器傳輸?shù)臄?shù)據(jù)。要解決同步阻塞這個(gè)問題可以去了解JAVA NIO。
Socket客戶端代碼如下:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class Client{ public static void main(String[] args) throws IOException { //創(chuàng)建連接指定Ip和端口的socket Socket socket = new Socket("127.0.0.1",5200); //獲取系統(tǒng)標(biāo)準(zhǔn)輸入流 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(socket.getOutputStream()); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); //創(chuàng)建一個(gè)線程用于讀取服務(wù)器的信息 new Thread(new Runnable() { @Override public void run() { try { while (true){ System.out.println(in.readLine()); } } catch (IOException e) { e.printStackTrace(); } } }).start(); //寫信息給客戶端 String line = reader.readLine(); while (!"end".equalsIgnoreCase(line)){ //將從鍵盤獲取的信息給到服務(wù)器 out.println(line); out.flush(); //顯示輸入的信息 line = reader.readLine(); } out.close(); in.close(); socket.close(); } }
由于要接收多個(gè)客戶端的請求,因此服務(wù)端需要多個(gè)線程進(jìn)行分別來接收客戶端的請求。
Socket服務(wù)端代碼如下:
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.List; import java.util.Vector; public class Servers { //將接收到的socket變成一個(gè)集合 protected static List<Socket> sockets = new Vector<>(); public static void main(String[] args) throws IOException { //創(chuàng)建服務(wù)端 ServerSocket server = new ServerSocket(5200); boolean flag = true; //接受客戶端請求 while (flag){ try { //阻塞等待客戶端的連接 Socket accept = server.accept(); synchronized (sockets){ sockets.add(accept); } //多個(gè)服務(wù)器線程進(jìn)行對客戶端的響應(yīng) Thread thread = new Thread(new ServerThead(accept)); thread.start(); //捕獲異常。 }catch (Exception e){ flag = false; e.printStackTrace(); } } //關(guān)閉服務(wù)器 server.close(); } }
Server線程代碼如下:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; /** * 服務(wù)器線程,主要來處理多個(gè)客戶端的請求 */ public class ServerThead extends Servers implements Runnable{ Socket socket; String socketName; public ServerThead(Socket socket){ this.socket = socket; } @Override public void run() { try { BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); //設(shè)置該客戶端的端點(diǎn)地址 socketName = socket.getRemoteSocketAddress().toString(); System.out.println("Client@"+socketName+"已加入聊天"); print("Client@"+socketName+"已加入聊天"); boolean flag = true; while (flag) { //阻塞,等待該客戶端的輸出流 String line = reader.readLine(); //若客戶端退出,則退出連接。 if (line == null){ flag = false; continue; } String msg = "Client@"+socketName+":"+line; System.out.println(msg); //向在線客戶端輸出信息 print(msg); } closeConnect(); } catch (IOException e) { try { closeConnect(); } catch (IOException e1) { e1.printStackTrace(); } } } /** * 向所有在線客戶端socket轉(zhuǎn)發(fā)消息 * @param msg * @throws IOException */ private void print(String msg) throws IOException { PrintWriter out = null; synchronized (sockets){ for (Socket sc : sockets){ out = new PrintWriter(sc.getOutputStream()); out.println(msg); out.flush(); } } } /** * 關(guān)閉該socket的連接 * @throws IOException */ public void closeConnect() throws IOException { System.out.println("Client@"+socketName+"已退出聊天"); print("Client@"+socketName+"已退出聊天"); //移除沒連接上的客戶端 synchronized (sockets){ sockets.remove(socket); } socket.close(); } }
由于要接收多個(gè)客戶端的信息,并轉(zhuǎn)發(fā)到每一個(gè)已經(jīng)連接上的客戶端,因此創(chuàng)建了一個(gè)Vector集合來保存每一個(gè)客戶端Socket,由于是多個(gè)線程同時(shí)對這個(gè)Vector集合進(jìn)行操作,因此加上synchronized關(guān)鍵字保證同步安全。
先運(yùn)行服務(wù)器端,然后在運(yùn)行多個(gè)客戶端就可以進(jìn)行多人聊天了。
下面是運(yùn)行的結(jié)果。
客戶端2
客戶端1
客戶端3
服務(wù)端
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java+socket實(shí)現(xiàn)簡易局域網(wǎng)聊天室
- Java Socket實(shí)現(xiàn)聊天室附1500行源代碼
- java實(shí)現(xiàn)多人聊天工具(socket+多線程)
- java課程設(shè)計(jì)做一個(gè)多人聊天室(socket+多線程)
- Java Socket+多線程實(shí)現(xiàn)多人聊天室功能
- Java Socket實(shí)現(xiàn)多人聊天系統(tǒng)
- Java Socket模擬實(shí)現(xiàn)聊天室
- Java Socket實(shí)現(xiàn)簡易聊天室
- Java socket通信模擬QQ實(shí)現(xiàn)多人聊天室
相關(guān)文章
Java Spring詳解如何配置數(shù)據(jù)源注解開發(fā)以及整合Junit
Spring 是目前主流的 Java Web 開發(fā)框架,是 Java 世界最為成功的框架。該框架是一個(gè)輕量級的開源框架,具有很高的凝聚力和吸引力,本篇文章帶你了解如何配置數(shù)據(jù)源、注解開發(fā)以及整合Junit2021-10-10詳解Java中CountDownLatch異步轉(zhuǎn)同步工具類
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著CountDownLatch異步轉(zhuǎn)同步工具類展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06myBatis組件教程之緩存的實(shí)現(xiàn)與使用
這篇文章主要給大家介紹了關(guān)于myBatis組件教程之緩存的實(shí)現(xiàn)與使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11RocketMQ實(shí)現(xiàn)消息分發(fā)的步驟
RocketMQ 實(shí)現(xiàn)消息分發(fā)的核心機(jī)制是通過 Topic、Queue 和 Consumer Group 的配合實(shí)現(xiàn)的,下面給大家介紹RocketMQ實(shí)現(xiàn)消息分發(fā)的步驟,感興趣的朋友一起看看吧2024-03-03基于list stream: reduce的使用實(shí)例
這篇文章主要介紹了list stream: reduce的使用實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09