java小程序---簡陋版多人聊天室


功能需求:

  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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM