java socket實(shí)現(xiàn)聊天室 java實(shí)現(xiàn)多人聊天功能
用java socket做一個聊天室,實(shí)現(xiàn)多人聊天的功能??戳藰O客學(xué)院的視頻后跟著敲的。(1DAY)
服務(wù)端:
1. 先寫服務(wù)端的類MyServerSocket,里面放一個監(jiān)聽線程,一啟動就好
2. 實(shí)現(xiàn)服務(wù)端監(jiān)聽類ServerListener.java,用accept來監(jiān)聽,一旦有客戶端連上,生成新的socket,就新建個線程實(shí)例ChatSocket。啟動線程后就把線程交給ChatManager管理
3. 在ChatSocket中實(shí)現(xiàn)從客戶端讀取內(nèi)容,把讀取到的內(nèi)容發(fā)給集合內(nèi)所有的客戶端
4. ChatManager里面用vector來管理socket線程實(shí)例ChatSocket,并實(shí)現(xiàn)發(fā)送信息給其他的客戶端
客戶端:
1. 新建一個繼承JFrame的MainWindow.java類,主要實(shí)現(xiàn)聊天窗口的UI,以及事件響應(yīng)。
2. 新建StartClient.java類,把MainWindow中生成MainWindow主方法部分代碼拷貝過來,這樣就能在主程序中把窗體執(zhí)行出來了。
3. 新建ChatManager(需要單例化的類)管理socket,實(shí)現(xiàn)聊天的輸入輸出功能。最后記得在1中新建窗口后,傳一份frame的引用到ChatManager中,才能實(shí)現(xiàn)ChatManager對界面的顯示。
工程結(jié)構(gòu)如圖
以下為代碼
服務(wù)端:
1. 先寫服務(wù)端的類MyServerSocket,里面放一個監(jiān)聽線程,一啟動就好
package com.starnet.testserversocket.main; public class MyServerSocket { public static void main(String[] args) { new ServerListener().start(); } }
2.實(shí)現(xiàn)服務(wù)端監(jiān)聽類ServerListener.java,用accept來監(jiān)聽,一旦有客戶端連上,生成新的socket,就新建個線程實(shí)例ChatSocket。啟動線程后就把線程交給ChatManager管理
package com.starnet.testserversocket.main; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import javax.swing.JOptionPane; public class ServerListener extends Thread { public void run() { try { ServerSocket serverSocket = new ServerSocket(23456); while (true) { // block Socket socket = serverSocket.accept(); // 建立鏈接 JOptionPane.showMessageDialog(null, "有客戶端連到本機(jī)23456端口"); //將socket傳遞給新的線程 ChatSocket cs= new ChatSocket(socket); cs.start(); ChatManager.getChatManager().add(cs); } } catch (IOException e) { e.printStackTrace(); } } }
3.在ChatSocket中實(shí)現(xiàn)從客戶端讀取內(nèi)容,把讀取到的內(nèi)容發(fā)給集合內(nèi)所有的客戶端
package com.starnet.testserversocket.main; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.Socket; /*每一個連上的客戶端,服務(wù)器都有一個線程為之服務(wù)*/ public class ChatSocket extends Thread { Socket socket; public ChatSocket(Socket s) { this.socket = s; } //發(fā)送數(shù)據(jù) public void out(String out) { try { socket.getOutputStream().write(out.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //服務(wù)器會不斷地從客戶端讀取內(nèi)容,把讀取到的內(nèi)容發(fā)給集合內(nèi)所有的客戶端。 public void run() { try { //接收數(shù)據(jù) BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream(), "UTF-8")); String line=null; //發(fā)送讀到的內(nèi)容 while ((line = br.readLine())!=null) { System.out.println(line); ChatManager.getChatManager().publish(this, line); } br.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
4.ChatManager里面用vector來管理socket線程實(shí)例ChatSocket,并實(shí)現(xiàn)發(fā)送信息給其他的客戶端
package com.starnet.testserversocket.main; import java.util.Vector; //一個聊天服務(wù)器只能有一個manager,要單例化處理 public class ChatManager { private ChatManager(){} private static final ChatManager CM=new ChatManager(); public static ChatManager getChatManager(){ return CM; } Vector<ChatSocket> vector = new Vector<ChatSocket>(); /*增加ChatSocket 實(shí)例到vector中*/ public void add(ChatSocket cs){ vector.add(cs); } /*發(fā)布消息給其他客戶端 *ChatSocket cs: 調(diào)用publish的線程 *msg:要發(fā)送的信息 */ public void publish(ChatSocket cs, String msg){ for (int i = 0; i < vector.size(); i++) { ChatSocket csTemp = vector.get(i); if (!cs.equals(csTemp)) { csTemp.out(msg+"\n");//不用發(fā)送給自己。 } } } }
客戶端:
1. 新建一個繼承JFrame的MainWindow.java類,主要實(shí)現(xiàn)聊天窗口的UI,以及事件響應(yīng)。
package com.starnet.javaclient.view; import java.awt.BorderLayout; import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import javax.swing.JTextArea; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; import javax.swing.JTextField; import javax.swing.JButton; import javax.swing.LayoutStyle.ComponentPlacement; import com.starnet.javaclient.main.ChatManager; import com.sun.xml.internal.ws.client.SenderException; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class MainWindow extends JFrame { /** * */ private static final long serialVersionUID = 1L; private JPanel contentPane; private JTextArea txt; private JTextField txtip; private JTextField txtSend; /** * Create the frame. */ public MainWindow() { setAlwaysOnTop(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); txt = new JTextArea(); txt.setText("ready..."); txtip = new JTextField(); txtip.setText("127.0.0.1"); txtip.setColumns(10); JButton btnConnect = new JButton("connect"); btnConnect.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { ChatManager.getChatManager().connect(txtip.getText()); } }); txtSend = new JTextField(); txtSend.setText("hello"); txtSend.setColumns(10); JButton btnSend = new JButton("send"); btnSend.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { ChatManager.getChatManager().send(txtSend.getText()); appendText("我說: "+txtSend.getText()); txtSend.setText(""); } }); GroupLayout gl_contentPane = new GroupLayout(contentPane); gl_contentPane.setHorizontalGroup( gl_contentPane.createParallelGroup(Alignment.LEADING) .addGroup(Alignment.TRAILING, gl_contentPane.createSequentialGroup() .addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING) .addGroup(gl_contentPane.createSequentialGroup() .addComponent(txtSend, GroupLayout.DEFAULT_SIZE, 325, Short.MAX_VALUE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(btnSend, GroupLayout.PREFERRED_SIZE, 109, GroupLayout.PREFERRED_SIZE)) .addGroup(Alignment.LEADING, gl_contentPane.createSequentialGroup() .addComponent(txtip, GroupLayout.PREFERRED_SIZE, 294, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(btnConnect, GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE)) .addComponent(txt, GroupLayout.DEFAULT_SIZE, 434, Short.MAX_VALUE)) .addContainerGap()) ); gl_contentPane.setVerticalGroup( gl_contentPane.createParallelGroup(Alignment.LEADING) .addGroup(gl_contentPane.createSequentialGroup() .addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE) .addComponent(txtip, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(btnConnect)) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(txt, GroupLayout.DEFAULT_SIZE, 198, Short.MAX_VALUE) .addPreferredGap(ComponentPlacement.RELATED) .addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING) .addComponent(btnSend) .addComponent(txtSend, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))) ); contentPane.setLayout(gl_contentPane); } /*客戶端發(fā)送的內(nèi)容添加到中間的txt控件中*/ public void appendText(String in) { txt.append("\n" + in); } }
2.新建StartClient.java類,把MainWindow中生成MainWindow主方法部分代碼拷貝過來,這樣就能在主程序中把窗體執(zhí)行出來了。
package com.starnet.javaclient.main; import java.awt.EventQueue; import com.starnet.javaclient.view.MainWindow; public class StartClient { public static void main(String[] args) { /*先新建一個jframe,然后把自動生成的代碼貼過來*/ EventQueue.invokeLater(new Runnable() { public void run() { try { MainWindow frame = new MainWindow(); frame.setVisible(true); //創(chuàng)建完這個frame以后,傳一份window的引用到ChatManager去 ChatManager.getChatManager().setWindow(frame); } catch (Exception e) { e.printStackTrace(); } } }); } }
3.新建ChatManager(需要單例化的類)管理socket,實(shí)現(xiàn)聊天的輸入輸出功能。最后記得在1中新建窗口后,傳一份frame的引用到ChatManager中,才能實(shí)現(xiàn)ChatManager對界面的顯示。
package com.starnet.javaclient.main; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; import com.starnet.javaclient.view.MainWindow; public class ChatManager { private ChatManager(){} private static final ChatManager instance=new ChatManager(); public static ChatManager getChatManager(){ return instance; } MainWindow window;//為了能在界面上顯示服務(wù)器發(fā)來的信息,就需要傳一個MainWindow的引用進(jìn)來 Socket socket; private String IP; BufferedReader bReader; PrintWriter pWriter; public void setWindow(MainWindow window) { this.window = window; window.appendText("文本框已經(jīng)和chatManager綁定了"); } public void connect(String ip) { this.IP = ip; new Thread(){ @Override public void run() { //實(shí)現(xiàn)網(wǎng)絡(luò)方法 try { socket = new Socket(IP, 23456); //輸出流 pWriter = new PrintWriter( new OutputStreamWriter( socket.getOutputStream())); //輸入流 bReader = new BufferedReader( new InputStreamReader( socket.getInputStream())); String line = null; //如果讀取數(shù)據(jù)為空 while ((line = bReader.readLine())!=null) { window.appendText("收到: "+line); } //讀完數(shù)據(jù)之后要關(guān)閉 pWriter.close(); bReader.close(); pWriter = null; bReader = null; } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } public void send(String sendMsg){ if (pWriter!=null) { pWriter.write(sendMsg+"\n"); pWriter.flush(); } else { window.appendText("當(dāng)前鏈接已經(jīng)中斷..."); } } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 基于java編寫局域網(wǎng)多人聊天室
- java編程實(shí)現(xiàn)多人聊天室功能
- Java基于Tcp/ip連接的多人交互聊天室
- java使用MulticastSocket實(shí)現(xiàn)基于廣播的多人聊天室
- Java SE實(shí)現(xiàn)多人聊天室功能
- Java NIO Selector用法詳解【含多人聊天室實(shí)例】
- java實(shí)現(xiàn)多人聊天工具(socket+多線程)
- Java多線程實(shí)現(xiàn)多人聊天室功能
- Java基于中介者模式實(shí)現(xiàn)多人聊天室功能示例
- java實(shí)現(xiàn)多人聊天系統(tǒng)
相關(guān)文章
Spring中的兩種代理JDK和CGLIB的區(qū)別淺談
本篇文章中主要介紹了Spring中的兩種代理JDK和CGLIB的區(qū)別淺談,詳解的介紹了JDK和CGLIB的原理和方法,有需要的朋友可以了解一下2017-04-04使用IDEA創(chuàng)建一個vert.x項(xiàng)目的方法
這篇文章主要介紹了使用IDEA創(chuàng)建一個vert.x項(xiàng)目的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09Java算法之?dāng)?shù)組冒泡排序代碼實(shí)例講解
這篇文章主要介紹了Java算法之?dāng)?shù)組冒泡排序代碼實(shí)例講解,文中用代碼舉例講解的很清晰,有感興趣的同學(xué)可以研究下2021-03-03SpringBoot實(shí)現(xiàn)定時(shí)任務(wù)動態(tài)管理示例
這篇文章主要為大家介紹了SpringBoot實(shí)現(xiàn)定時(shí)任務(wù)動態(tài)管理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06spring?boot常見get?、post請求參數(shù)處理、參數(shù)注解校驗(yàn)、參數(shù)自定義注解校驗(yàn)問題解析
這篇文章主要介紹了spring?boot常見get?、post請求參數(shù)處理、參數(shù)注解校驗(yàn)、參數(shù)自定義注解校驗(yàn),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09Spring boot中使用Spring-data-jpa方便快捷的訪問數(shù)據(jù)庫(推薦)
Spring Data JPA 是 Spring 基于 ORM 框架、JPA 規(guī)范的基礎(chǔ)上封裝的一套JPA應(yīng)用框架,可使開發(fā)者用極簡的代碼即可實(shí)現(xiàn)對數(shù)據(jù)的訪問和操作。這篇文章主要介紹了Spring-boot中使用Spring-data-jpa方便快捷的訪問數(shù)據(jù)庫,需要的朋友可以參考下2018-05-05