功能需求:
1 每運行一次主函數,創建一個客戶端聊天界面;
2 客戶端界面分三塊,公屏(顯示所有客戶端發送的信息),私屏(用於輸入個人想要發送的信息),發送按鈕(點擊一次,將客戶端信息發送到服務端)
3 進入客戶端時公屏提示 歡迎xxx來到多人聊天室,關閉客戶端時提示 xxx已離開聊天室
4 客戶端展示在文末,源文件地址也在文末,可以直接轉尾部
============================================================================
所需知識:
1 IO流基礎知識,用於讀寫發送的信息
2 Jframe jpane,用於創建圖形界面
3 socket基礎知識,用於創建客戶端,服務端,互相傳遞信息
4 線程基礎知識
5 計時器基礎知識
======================================================================
主要思路:
1 創建客戶端界面,
2 在界面中創建客戶端,每點擊一次,就發送信息到服務端
3 服務端一直開啟,持續接受客戶端信息.然后將接受到的信息發送到所有客戶端
4 客戶端將服務器發送的信息顯示在公屏
===========================================================================
代碼如下:
第一步:畫客戶端外邊框
/** * @Title: chatJFrame.java * @Package view * @Description: * @author Mr.Yao * @date 2019年8月28日下午4:53:47 * @version V1.0 */ package chatview; import java.awt.Dimension; import java.awt.Toolkit; import java.util.Scanner; import javax.swing.JFrame; /** * @ClassName: chatJFrame * @Description: 繼承JFrame,畫聊天界面外邊框 * @author Mr.Yao * @date 2019年8月28日下午4:53:47 * */ public class ChatJFrame extends JFrame { //重寫構造方法 public ChatJFrame() { //輸出讓用戶輸入用戶名,作為之后客戶端的名字 System.out.println("請輸入用戶名"); Scanner input=new Scanner(System.in); String name=input.next(); //設置聊天室的名稱 this.setTitle(name); //獲取屏幕 Toolkit dt = Toolkit.getDefaultToolkit(); Dimension ss = dt.getScreenSize(); //獲取屏幕寬高 int width = (int)ss.getWidth(); int height = (int)ss.getHeight(); //設置居中和寬高 this.setBounds((width - 500) /2,(height - 500)/2,500,500); //添加chatJPanl對象,添加畫布,並傳入姓名 this.add(new ChatJPanel(name)); //設置禁止窗口縮放 this.setResizable(false); //當關閉窗口時關閉JVm, this.setDefaultCloseOperation(this.EXIT_ON_CLOSE); //設置可見 this.setVisible(true); } }
=====================================================================
第二步 創建畫布,並建立客戶端
如何做到點擊send按鈕發送信息-?---------->建按鈕點擊事件,點擊一次就獲取當前文本輸入框的信息,並用write()方法寫出到服務端
如何做到持續接受服務端發來的信息?----------->利用計時器,每0.5s執行一次,如果服務端有發送信息,則將其顯示到公屏中
/** * @Title: chatJPane.java * @Package view * @Description: * @author Mr.Yao * @date 2019年8月28日下午4:54:05 * @version V1.0 */ package chatview; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.Timer; import java.util.TimerTask; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JTextArea; /** * @ClassName: chatJPane * @Description: 繼承JPanl類,用於畫圖形中三塊區域,並建立客戶端發送信息和接受信息的功能 * @author Mr.Yao * @date 2019年8月28日下午4:54:05 * */ public class ChatJPanel extends JPanel{ //聲明姓名字符串,用於接收chatJFrame傳過來的用戶姓名 public String name; //添加文本域,作為聊天信息公屏框 public JTextArea screen; //添加文本域,作為用戶信息輸入框 public JTextArea input; //添加發送按鈕,點擊按鈕,將輸入框信息發送出去 public JButton send; //申明客戶端 public Socket socket; //申明客戶端輸出,輸入流 OutputStream os; InputStream is; //無參構造方法 public ChatJPanel() {} //有參構造 public ChatJPanel(String name) { //接收用戶姓名 this.name=name; //取消流式布局 this.setLayout(null); //創建公屏並設置寬高 screen=new JTextArea(); screen.setBounds(20, 20, 450, 280); this.add(screen); //創建輸入框並設置寬高 input=new JTextArea(); input.setBounds(20,320,300,120); this.add(input); //創建按鈕,並設置寬高 //按鈕對象 send = new JButton(); send.setBounds(340, 320, 100, 120); send.setText("SEND"); this.add(send); //新建客戶端對象,並設置ip地址和端口號 try { socket=new Socket("127.0.0.01",12321); //獲取客戶端輸入 輸出流 os=socket.getOutputStream(); is=socket.getInputStream(); //輸出歡迎xxx來到聊天室 String s="歡迎"+name+"來到聊天室!!!!"; os.write(s.getBytes()); os.flush(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } /*給按鈕添加點擊功能,點擊按鈕時將輸入框信息發送到服務端*/ send.addActionListener(new ActionListener() { @Override //重寫方法 public void actionPerformed(ActionEvent e) { //獲取輸入框當前的內容,並加上用戶姓名 String text = name+"說:"+input.getText(); //將輸入框輸出到服務端 try { //寫出數據 os.write(text.getBytes()); //刷新 os.flush(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } //清空輸入框 input.setText(""); } }); //創建計時器,每500毫秒啟動一次,接受服務端發出來的信息 new Timer().schedule(new TimerTask() { @Override //重寫方法,接受服務端的信息 public void run() { // TODO Auto-generated method stub //定義字符串,接受服務器返回的信息 String text=""; try { //創建byte數組,保存服務器返回的字節信息 byte[] b=new byte[1024]; //定義變量記錄讀取的字節數 int len=-1; //讀取服務器返回字節 len=is.read(b); //轉換為字符 text=new String(b,0,len); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(text!="") { //添加到屏幕 screen.append(text+"\n"); } } },500,500); } }
===========================================================================
第三步 創建服務端
如何做到服務持續接受不同客戶端信息並發送到所有客戶端?-------> 服務一直開啟,利用死循環 while()不停接受客戶端soket,每接受一個就添加到一個集合中,並創建一個線程.線程的內容是遍歷集合,將服務端接受的信息發送到所有客戶端
創建集合,用於保存服務端接受到的socket
/** * @Title: ServerList.java * @Package chatserver * @Description: * @author Mr.Yao * @date 2019年8月28日下午7:56:41 * @version V1.0 */ package chatserver; import java.net.Socket; import java.util.ArrayList; /** * @ClassName: ServerList * @Description: 創建集合,保存每個客戶端的socket * @author Mr.Yao * @date 2019年8月28日下午7:56:41 * */ public class ServerList { //創建集合 public static ArrayList<Socket> list=new ArrayList<Socket>(); }
server類用於接受客戶端並開啟線程,還需建立一個線程類,並重寫run方法,重寫后的run方法用於遍歷集合並將信息輸出到所有客戶端
/** * @Title: Server.java * @Package chatserver * @Description: * @author Mr.Yao * @date 2019年8月28日下午7:53:37 * @version V1.0 */ package chatserver; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * @ClassName: Server * @Description: 創建服務器,持續接受客戶端信息 * @author Mr.Yao * @date 2019年8月28日下午7:53:37 * */ public class Server { public static void main(String[] args) { // TODO Auto-generated method stub //創建服務器 ServerSocket ss = null; try { ss=new ServerSocket(12321); //循環接受客戶端 while(true) { Socket socket = ss.accept(); //將socket添加到數組 ServerList.list.add(socket); //創建匿名線程並啟動 new Thread(new ServerThread(socket)).start(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
ServerThread類實現了runnable接口,重寫run方法
/** * @Title: ServerThread.java * @Package chatserver * @Description: * @author Mr.Yao * @date 2019年8月29日上午11:58:47 * @version V1.0 */ package chatserver; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /** * @ClassName: ServerThread * @Description: 創建線程類,用於循環接受客戶端的信息和將信息發送到所有的客戶端 * @author Mr.Yao * @date 2019年8月29日上午11:58:47 * */ public class ServerThread implements Runnable { //聲明變量,接受用戶客戶端名稱,用於輸出XXX下線了 public String name=null; //聲明socket對象 public Socket socket; //無參構造 public ServerThread() {} //傳參構造 public ServerThread(Socket socket) { this.socket=socket; } //重寫run方法 @Override public void run() { // TODO Auto-generated method stub //創建輸入流 try { InputStream is=socket.getInputStream(); //持續接受客戶端信息 while(true) { //接受客戶端信息 byte[] b=new byte[1024]; int len=-1; len=is.read(b); //獲取客戶名稱,從第一句 歡迎xxx來到客戶端中截取出名稱 String string=new String(b,0,len); if(string.contains("歡迎")&&name==null) { //截取名稱 name=string.substring(2,string.indexOf("來")); } //將該信息發送到每個客戶端 for(Socket socket:ServerList.list) { //創建輸出流 OutputStream os=socket.getOutputStream(); //輸出信息 os.write(b, 0, len); //刷新 os.flush(); } } }catch (IOException e) { // TODO: handle exception //出現異常,說明該客戶端已關閉,向其他在線客戶端發送信息:xxx下線了 // e.printStackTrace(); //將集合中的已關閉的socket對象刪除, ServerList.list.remove(this.socket); //循環輸出信息 for(Socket socket:ServerList.list) { //創建輸出流 try { OutputStream os = socket.getOutputStream(); //輸出信息 os.write((name+"下線了").getBytes()); //刷新 os.flush(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } } }
第四步 創建啟動類,寫主函數
/** * @Title: ChatStart.java * @Package chatstart * @Description: * @author Mr.Yao * @date 2019年8月28日下午7:51:14 * @version V1.0 */ package chatstart; import chatview.ChatJFrame; /** * @ClassName: ChatStart * @Description: 主方法,程序入口 * @author Mr.Yao * @date 2019年8月28日下午7:51:14 * */ public class ChatStart { public static void main(String[] args) { // TODO Auto-generated method stub //創建jf邊框對象 ChatJFrame jf=new ChatJFrame(); } }
==============================================================================================
運行效果展示:
---->需要先運行server,開啟服務端.然后運行主函數,每運行一次,就會創建一個客戶端
-----源文件目錄結構:
源碼:
鏈接:https://pan.baidu.com/s/18aPqsoJsP4ZZYf6ZkWzU-g
提取碼:exva