設計一個聊天服務器

系統基本功能描述html

 

客戶端能夠實現註冊,即時聊天,相互之間收發文件,發送截圖,查看歷史聊天記錄java

等功能。收發消息時,能夠實現離線接收。數據庫

 

服務器端應當創建一個數組

ServerSocket服務器

app

而且不斷進行偵聽是否有客戶端鏈接或者斷開eclipse

鏈接socket

(ide

包括判斷沒有響應的鏈接超時this

)

。服務器端應當是一個信息發送中心,全部客戶端的

信息都傳到服務器端,由服務器端根據要求分發信息。

 

在後臺管理系統,能夠到對用戶進行增刪改查,查看在線用戶,和踢用戶下線

本系統要實現的功能以下:

 

1)

註冊

 

服務器收到用戶的註冊請求,便開始接受客戶傳遞的信息,諸如客戶的呢稱,性別,

籍貫,我的資料等,接受完畢後,便經過

JDBC

與後臺數據庫鏈接,而後向數據庫添加記

錄,若是成功,便向客戶返回其號碼。客戶收到服務器返回的信息後,便打開窗口登錄。

 

 

2)

登錄

 

在客戶端,

用戶輸入其號碼和密碼,

而後創建與服務器的鏈接,

告訴服務器我要登陸,

服務器收到後,

開始經過

JDBC

讀取數據庫,

而後與用戶輸入的信息進行比對,

若是成功,

便打開主程序窗口。而後客戶向服務器請求讀取好友名單,服務器收到該請求,從數據庫

中取出好友列表,而後向客戶端發送這些信息,客戶收到後就在主窗口顯示好友。

 

3)

聊天

 

客戶端首先發送消息到服務器端,服務器端根據發送人信息和接收者信息來轉發。例

如服務器接收到一個

A

發給

B

的消息,先判斷

B

是否已經在線,若是在線就將信息發送

過去。

若是

B

不在線則把信息儲存在服務器,

B

上線了在發送給他。

B

接收到

A

發來的

信息,若是是未創建對話窗口,則自動打開顯示。

 

 

4)

發送截圖

 

客戶端

A

點擊截圖按鈕,將屏幕鎖定,截取圖片,將圖片儲存在

byte[]

數組中發送到

服務器端。服務器端根據發送人信息和接收者信息來轉發。

B

接收到

A

發來的截圖信息,

會根據

byte[]

構造圖片,將圖片顯示出來。一樣,若是是未創建對話窗口,則自動打開顯

示。

 

5)

發送文件

 

客戶端

A

點擊發送文件按鍵,從本地選擇文件,將文件在

byte[]

數組中分批次發送到

服務器端。服務器端根據發送人信息和接收者信息來轉發。

B

接收到

A

發來的文件信息,

會根據文件發送的狀態和

byte[]

構造文件。

6)

日誌

 

客戶端發送和接收到的信息都會儲存在文本文檔中。默認儲存在

C

盤下面,會以用戶

的登陸帳號爲名。

 

 

7)

對用戶的操做

 

 

管理員經過

B/S

的系統對用戶進行增長,

修改,

刪除,

查找等操做,

對系統進行維護。

 

 

8)

在線用戶的操做

 

 

管理員經過

B/S

的系統對在線用戶操做,能夠踢用戶下線。

 

 

界面是用swing寫的,還不懶,簡約大方。有圖有真相:

 

 

 

正如上圖所示,這個程序分爲 服務器端和客戶端,說白了就是 兩個main class,用eclipse直接運行之。。。。。

 

           聊天室的設計思想是 :在局域網下, 利用socket進行鏈接通訊,當服務器端啓動的時候,利用Thread線程不停的等待客戶端的連接;當有客戶端開啓連

接的時候,服務器端經過IO流反饋「上線用戶」信息給客戶端,客戶端也使用線程不停的接收服務器的信息,從而實現多人在線聊天功能。

 

程序中有三個類,分別 Server.Java(服務器端)、Client(客戶端)、User.java(javabean)。代碼以下:

 

Server.java(服務器端):

[html] view plain copy

 

  1. import java.awt.BorderLayout;  
  2. import java.awt.Color;  
  3. import java.awt.GridLayout;  
  4. import java.awt.Toolkit;  
  5. import java.awt.event.ActionEvent;  
  6. import java.awt.event.ActionListener;  
  7. import java.awt.event.WindowAdapter;  
  8. import java.awt.event.WindowEvent;  
  9. import java.io.BufferedReader;  
  10. import java.io.IOException;  
  11. import java.io.InputStreamReader;  
  12. import java.io.PrintWriter;  
  13. import java.net.BindException;  
  14. import java.net.ServerSocket;  
  15. import java.net.Socket;  
  16. import java.util.ArrayList;  
  17. import java.util.StringTokenizer;  
  18.   
  19. import javax.swing.DefaultListModel;  
  20. import javax.swing.JButton;  
  21. import javax.swing.JFrame;  
  22. import javax.swing.JLabel;  
  23. import javax.swing.JList;  
  24. import javax.swing.JOptionPane;  
  25. import javax.swing.JPanel;  
  26. import javax.swing.JScrollPane;  
  27. import javax.swing.JSplitPane;  
  28. import javax.swing.JTextArea;  
  29. import javax.swing.JTextField;  
  30. import javax.swing.border.TitledBorder;  
  31.   
  32. public class Server {  
  33.   
  34.     private JFrame frame;  
  35.     private JTextArea contentArea;  
  36.     private JTextField txt_message;  
  37.     private JTextField txt_max;  
  38.     private JTextField txt_port;  
  39.     private JButton btn_start;  
  40.     private JButton btn_stop;  
  41.     private JButton btn_send;  
  42.     private JPanel northPanel;  
  43.     private JPanel southPanel;  
  44.     private JScrollPane rightPanel;  
  45.     private JScrollPane leftPanel;  
  46.     private JSplitPane centerSplit;  
  47.     private JList userList;  
  48.     private DefaultListModel listModel;  
  49.   
  50.     private ServerSocket serverSocket;  
  51.     private ServerThread serverThread;  
  52.     private ArrayList<ClientThread> clients;  
  53.   
  54.     private boolean isStart = false;  
  55.   
  56.     // 主方法,程序執行入口  
  57.     public static void main(String[] args) {  
  58.         new Server();  
  59.     }  
  60.   
  61.     // 執行消息發送  
  62.     public void send() {  
  63.         if (!isStart) {  
  64.             JOptionPane.showMessageDialog(frame, "服務器還未啓動,不能發送消息!", "錯誤",  
  65.                     JOptionPane.ERROR_MESSAGE);  
  66.             return;  
  67.         }  
  68.         if (clients.size() == 0) {  
  69.             JOptionPane.showMessageDialog(frame, "沒有用戶在線,不能發送消息!", "錯誤",  
  70.                     JOptionPane.ERROR_MESSAGE);  
  71.             return;  
  72.         }  
  73.         String message = txt_message.getText().trim();  
  74.         if (message == null || message.equals("")) {  
  75.             JOptionPane.showMessageDialog(frame, "消息不能爲空!", "錯誤",  
  76.                     JOptionPane.ERROR_MESSAGE);  
  77.             return;  
  78.         }  
  79.         sendServerMessage(message);// 羣發服務器消息  
  80.         contentArea.append("服務器說:" + txt_message.getText() + "\r\n");  
  81.         txt_message.setText(null);  
  82.     }  
  83.   
  84.     // 構造放法  
  85.     public Server() {  
  86.         frame = new JFrame("服務器");  
  87.         // 更改JFrame的圖標:  
  88.         //frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));  
  89.         frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.png")));  
  90.         contentArea = new JTextArea();  
  91.         contentArea.setEditable(false);  
  92.         contentArea.setForeground(Color.blue);  
  93.         txt_message = new JTextField();  
  94.         txt_max = new JTextField("30");  
  95.         txt_port = new JTextField("6666");  
  96.         btn_start = new JButton("啓動");  
  97.         btn_stop = new JButton("中止");  
  98.         btn_send = new JButton("發送");  
  99.         btn_stop.setEnabled(false);  
  100.         listModel = new DefaultListModel();  
  101.         userList = new JList(listModel);  
  102.   
  103.         southPanel = new JPanel(new BorderLayout());  
  104.         southPanel.setBorder(new TitledBorder("寫消息"));  
  105.         southPanel.add(txt_message, "Center");  
  106.         southPanel.add(btn_send, "East");  
  107.         leftPanel = new JScrollPane(userList);  
  108.         leftPanel.setBorder(new TitledBorder("在線用戶"));  
  109.   
  110.         rightPanel = new JScrollPane(contentArea);  
  111.         rightPanel.setBorder(new TitledBorder("消息顯示區"));  
  112.   
  113.         centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,  
  114.                 rightPanel);  
  115.         centerSplit.setDividerLocation(100);  
  116.         northPanel = new JPanel();  
  117.         northPanel.setLayout(new GridLayout(1, 6));  
  118.         northPanel.add(new JLabel("人數上限"));  
  119.         northPanel.add(txt_max);  
  120.         northPanel.add(new JLabel("端口"));  
  121.         northPanel.add(txt_port);  
  122.         northPanel.add(btn_start);  
  123.         northPanel.add(btn_stop);  
  124.         northPanel.setBorder(new TitledBorder("配置信息"));  
  125.   
  126.         frame.setLayout(new BorderLayout());  
  127.         frame.add(northPanel, "North");  
  128.         frame.add(centerSplit, "Center");  
  129.         frame.add(southPanel, "South");  
  130.         frame.setSize(600, 400);  
  131.         //frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//設置全屏  
  132.         int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;  
  133.         int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;  
  134.         frame.setLocation((screen_width - frame.getWidth()) / 2,  
  135.                 (screen_height - frame.getHeight()) / 2);  
  136.         frame.setVisible(true);  
  137.   
  138.         // 關閉窗口時事件  
  139.         frame.addWindowListener(new WindowAdapter() {  
  140.             public void windowClosing(WindowEvent e) {  
  141.                 if (isStart) {  
  142.                     closeServer();// 關閉服務器  
  143.                 }  
  144.                 System.exit(0);// 退出程序  
  145.             }  
  146.         });  
  147.   
  148.         // 文本框按回車鍵時事件  
  149.         txt_message.addActionListener(new ActionListener() {  
  150.             public void actionPerformed(ActionEvent e) {  
  151.                 send();  
  152.             }  
  153.         });  
  154.   
  155.         // 單擊發送按鈕時事件  
  156.         btn_send.addActionListener(new ActionListener() {  
  157.             public void actionPerformed(ActionEvent arg0) {  
  158.                 send();  
  159.             }  
  160.         });  
  161.   
  162.         // 單擊啓動服務器按鈕時事件  
  163.         btn_start.addActionListener(new ActionListener() {  
  164.             public void actionPerformed(ActionEvent e) {  
  165.                 if (isStart) {  
  166.                     JOptionPane.showMessageDialog(frame, "服務器已處於啓動狀態,不要重複啓動!",  
  167.                             "錯誤", JOptionPane.ERROR_MESSAGE);  
  168.                     return;  
  169.                 }  
  170.                 int max;  
  171.                 int port;  
  172.                 try {  
  173.                     try {  
  174.                         max = Integer.parseInt(txt_max.getText());  
  175.                     } catch (Exception e1) {  
  176.                         throw new Exception("人數上限爲正整數!");  
  177.                     }  
  178.                     if (max <= 0) {  
  179.                         throw new Exception("人數上限爲正整數!");  
  180.                     }  
  181.                     try {  
  182.                         port = Integer.parseInt(txt_port.getText());  
  183.                     } catch (Exception e1) {  
  184.                         throw new Exception("端口號爲正整數!");  
  185.                     }  
  186.                     if (port <= 0) {  
  187.                         throw new Exception("端口號 爲正整數!");  
  188.                     }  
  189.                     serverStart(max, port);  
  190.                     contentArea.append("服務器已成功啓動!人數上限:" + max + ",端口:" + port  
  191.                             + "\r\n");  
  192.                     JOptionPane.showMessageDialog(frame, "服務器成功啓動!");  
  193.                     btn_start.setEnabled(false);  
  194.                     txt_max.setEnabled(false);  
  195.                     txt_port.setEnabled(false);  
  196.                     btn_stop.setEnabled(true);  
  197.                 } catch (Exception exc) {  
  198.                     JOptionPane.showMessageDialog(frame, exc.getMessage(),  
  199.                             "錯誤", JOptionPane.ERROR_MESSAGE);  
  200.                 }  
  201.             }  
  202.         });  
  203.   
  204.         // 單擊中止服務器按鈕時事件  
  205.         btn_stop.addActionListener(new ActionListener() {  
  206.             public void actionPerformed(ActionEvent e) {  
  207.                 if (!isStart) {  
  208.                     JOptionPane.showMessageDialog(frame, "服務器還未啓動,無需中止!", "錯誤",  
  209.                             JOptionPane.ERROR_MESSAGE);  
  210.                     return;  
  211.                 }  
  212.                 try {  
  213.                     closeServer();  
  214.                     btn_start.setEnabled(true);  
  215.                     txt_max.setEnabled(true);  
  216.                     txt_port.setEnabled(true);  
  217.                     btn_stop.setEnabled(false);  
  218.                     contentArea.append("服務器成功中止!\r\n");  
  219.                     JOptionPane.showMessageDialog(frame, "服務器成功中止!");  
  220.                 } catch (Exception exc) {  
  221.                     JOptionPane.showMessageDialog(frame, "中止服務器發生異常!", "錯誤",  
  222.                             JOptionPane.ERROR_MESSAGE);  
  223.                 }  
  224.             }  
  225.         });  
  226.     }  
  227.   
  228.     // 啓動服務器  
  229.     public void serverStart(int max, int port) throws java.net.BindException {  
  230.         try {  
  231.             clients = new ArrayList<ClientThread>();  
  232.             serverSocket = new ServerSocket(port);  
  233.             serverThread = new ServerThread(serverSocket, max);  
  234.             serverThread.start();  
  235.             isStart = true;  
  236.         } catch (BindException e) {  
  237.             isStart = false;  
  238.             throw new BindException("端口號已被佔用,請換一個!");  
  239.         } catch (Exception e1) {  
  240.             e1.printStackTrace();  
  241.             isStart = false;  
  242.             throw new BindException("啓動服務器異常!");  
  243.         }  
  244.     }  
  245.   
  246.     // 關閉服務器  
  247.     @SuppressWarnings("deprecation")  
  248.     public void closeServer() {  
  249.         try {  
  250.             if (serverThread != null)  
  251.                 serverThread.stop();// 中止服務器線程  
  252.   
  253.             for (int i = clients.size() - 1; i >= 0; i--) {  
  254.                 // 給全部在線用戶發送關閉命令  
  255.                 clients.get(i).getWriter().println("CLOSE");  
  256.                 clients.get(i).getWriter().flush();  
  257.                 // 釋放資源  
  258.                 clients.get(i).stop();// 中止此條爲客戶端服務的線程  
  259.                 clients.get(i).reader.close();  
  260.                 clients.get(i).writer.close();  
  261.                 clients.get(i).socket.close();  
  262.                 clients.remove(i);  
  263.             }  
  264.             if (serverSocket != null) {  
  265.                 serverSocket.close();// 關閉服務器端鏈接  
  266.             }  
  267.             listModel.removeAllElements();// 清空用戶列表  
  268.             isStart = false;  
  269.         } catch (IOException e) {  
  270.             e.printStackTrace();  
  271.             isStart = true;  
  272.         }  
  273.     }  
  274.   
  275.     // 羣發服務器消息  
  276.     public void sendServerMessage(String message) {  
  277.         for (int i = clients.size() - 1; i >= 0; i--) {  
  278.             clients.get(i).getWriter().println("服務器:" + message + "(多人發送)");  
  279.             clients.get(i).getWriter().flush();  
  280.         }  
  281.     }  
  282.   
  283.     // 服務器線程  
  284.     class ServerThread extends Thread {  
  285.         private ServerSocket serverSocket;  
  286.         private int max;// 人數上限  
  287.   
  288.         // 服務器線程的構造方法  
  289.         public ServerThread(ServerSocket serverSocket, int max) {  
  290.             this.serverSocket = serverSocket;  
  291.             this.max = max;  
  292.         }  
  293.   
  294.         public void run() {  
  295.             while (true) {// 不停的等待客戶端的連接  
  296.                 try {  
  297.                     Socket socket = serverSocket.accept();  
  298.                     if (clients.size() == max) {// 若是已達人數上限  
  299.                         BufferedReader r = new BufferedReader(  
  300.                                 new InputStreamReader(socket.getInputStream()));  
  301.                         PrintWriter w = new PrintWriter(socket  
  302.                                 .getOutputStream());  
  303.                         // 接收客戶端的基本用戶信息  
  304.                         String inf = r.readLine();  
  305.                         StringTokenizer st = new StringTokenizer(inf, "@");  
  306.                         User user = new User(st.nextToken(), st.nextToken());  
  307.                         // 反饋鏈接成功信息  
  308.                         w.println("MAX@服務器:對不起," + user.getName()  
  309.                                 + user.getIp() + ",服務器在線人數已達上限,請稍後嘗試鏈接!");  
  310.                         w.flush();  
  311.                         // 釋放資源  
  312.                         r.close();  
  313.                         w.close();  
  314.                         socket.close();  
  315.                         continue;  
  316.                     }  
  317.                     ClientThread client = new ClientThread(socket);  
  318.                     client.start();// 開啓對此客戶端服務的線程  
  319.                     clients.add(client);  
  320.                     listModel.addElement(client.getUser().getName());// 更新在線列表  
  321.                     contentArea.append(client.getUser().getName()  
  322.                             + client.getUser().getIp() + "上線!\r\n");  
  323.                 } catch (IOException e) {  
  324.                     e.printStackTrace();  
  325.                 }  
  326.             }  
  327.         }  
  328.     }  
  329.   
  330.     // 爲一個客戶端服務的線程  
  331.     class ClientThread extends Thread {  
  332.         private Socket socket;  
  333.         private BufferedReader reader;  
  334.         private PrintWriter writer;  
  335.         private User user;  
  336.   
  337.         public BufferedReader getReader() {  
  338.             return reader;  
  339.         }  
  340.   
  341.         public PrintWriter getWriter() {  
  342.             return writer;  
  343.         }  
  344.   
  345.         public User getUser() {  
  346.             return user;  
  347.         }  
  348.   
  349.         // 客戶端線程的構造方法  
  350.         public ClientThread(Socket socket) {  
  351.             try {  
  352.                 this.socket = socket;  
  353.                 reader = new BufferedReader(new InputStreamReader(socket  
  354.                         .getInputStream()));  
  355.                 writer = new PrintWriter(socket.getOutputStream());  
  356.                 // 接收客戶端的基本用戶信息  
  357.                 String inf = reader.readLine();  
  358.                 StringTokenizer st = new StringTokenizer(inf, "@");  
  359.                 user = new User(st.nextToken(), st.nextToken());  
  360.                 // 反饋鏈接成功信息  
  361.                 writer.println(user.getName() + user.getIp() + "與服務器鏈接成功!");  
  362.                 writer.flush();  
  363.                 // 反饋當前在線用戶信息  
  364.                 if (clients.size() > 0) {  
  365.                     String temp = "";  
  366.                     for (int i = clients.size() - 1; i >= 0; i--) {  
  367.                         temp += (clients.get(i).getUser().getName() + "/" + clients  
  368.                                 .get(i).getUser().getIp())  
  369.                                 + "@";  
  370.                     }  
  371.                     writer.println("USERLIST@" + clients.size() + "@" + temp);  
  372.                     writer.flush();  
  373.                 }  
  374.                 // 向全部在線用戶發送該用戶上線命令  
  375.                 for (int i = clients.size() - 1; i >= 0; i--) {  
  376.                     clients.get(i).getWriter().println(  
  377.                             "ADD@" + user.getName() + user.getIp());  
  378.                     clients.get(i).getWriter().flush();  
  379.                 }  
  380.             } catch (IOException e) {  
  381.                 e.printStackTrace();  
  382.             }  
  383.         }  
  384.   
  385.         @SuppressWarnings("deprecation")  
  386.         public void run() {// 不斷接收客戶端的消息,進行處理。  
  387.             String message = null;  
  388.             while (true) {  
  389.                 try {  
  390.                     message = reader.readLine();// 接收客戶端消息  
  391.                     if (message.equals("CLOSE"))// 下線命令  
  392.                     {  
  393.                         contentArea.append(this.getUser().getName()  
  394.                                 + this.getUser().getIp() + "下線!\r\n");  
  395.                         // 斷開鏈接釋放資源  
  396.                         reader.close();  
  397.                         writer.close();  
  398.                         socket.close();  
  399.   
  400.                         // 向全部在線用戶發送該用戶的下線命令  
  401.                         for (int i = clients.size() - 1; i >= 0; i--) {  
  402.                             clients.get(i).getWriter().println(  
  403.                                     "DELETE@" + user.getName());  
  404.                             clients.get(i).getWriter().flush();  
  405.                         }  
  406.   
  407.                         listModel.removeElement(user.getName());// 更新在線列表  
  408.   
  409.                         // 刪除此條客戶端服務線程  
  410.                         for (int i = clients.size() - 1; i >= 0; i--) {  
  411.                             if (clients.get(i).getUser() == user) {  
  412.                                 ClientThread temp = clients.get(i);  
  413.                                 clients.remove(i);// 刪除此用戶的服務線程  
  414.                                 temp.stop();// 中止這條服務線程  
  415.                                 return;  
  416.                             }  
  417.                         }  
  418.                     } else {  
  419.                         dispatcherMessage(message);// 轉發消息  
  420.                     }  
  421.                 } catch (IOException e) {  
  422.                     e.printStackTrace();  
  423.                 }  
  424.             }  
  425.         }  
  426.   
  427.         // 轉發消息  
  428.         public void dispatcherMessage(String message) {  
  429.             StringTokenizer stringTokenizer = new StringTokenizer(message, "@");  
  430.             String source = stringTokenizer.nextToken();  
  431.             String owner = stringTokenizer.nextToken();  
  432.             String content = stringTokenizer.nextToken();  
  433.             message = source + "說:" + content;  
  434.             contentArea.append(message + "\r\n");  
  435.             if (owner.equals("ALL")) {// 羣發  
  436.                 for (int i = clients.size() - 1; i >= 0; i--) {  
  437.                     clients.get(i).getWriter().println(message + "(多人發送)");  
  438.                     clients.get(i).getWriter().flush();  
  439.                 }  
  440.             }  
  441.         }  
  442.     }  
  443. }  


 

 

Client(客戶端):

[html] view plain copy

 

  1. import java.awt.BorderLayout;  
  2. import java.awt.Color;  
  3. import java.awt.GridLayout;  
  4. import java.awt.Toolkit;  
  5. import java.awt.event.ActionEvent;  
  6. import java.awt.event.ActionListener;  
  7. import java.awt.event.WindowAdapter;  
  8. import java.awt.event.WindowEvent;  
  9. import java.io.BufferedReader;  
  10. import java.io.IOException;  
  11. import java.io.InputStreamReader;  
  12. import java.io.PrintWriter;  
  13. import java.net.Socket;  
  14. import java.util.HashMap;  
  15. import java.util.Map;  
  16. import java.util.StringTokenizer;  
  17.   
  18. import javax.swing.DefaultListModel;  
  19. import javax.swing.JButton;  
  20. import javax.swing.JFrame;  
  21. import javax.swing.JLabel;  
  22. import javax.swing.JList;  
  23. import javax.swing.JOptionPane;  
  24. import javax.swing.JPanel;  
  25. import javax.swing.JScrollPane;  
  26. import javax.swing.JSplitPane;  
  27. import javax.swing.JTextArea;  
  28. import javax.swing.JTextField;  
  29. import javax.swing.border.TitledBorder;  
  30.   
  31. public class Client{  
  32.   
  33.     private JFrame frame;  
  34.     private JList userList;  
  35.     private JTextArea textArea;  
  36.     private JTextField textField;  
  37.     private JTextField txt_port;  
  38.     private JTextField txt_hostIp;  
  39.     private JTextField txt_name;  
  40.     private JButton btn_start;  
  41.     private JButton btn_stop;  
  42.     private JButton btn_send;  
  43.     private JPanel northPanel;  
  44.     private JPanel southPanel;  
  45.     private JScrollPane rightScroll;  
  46.     private JScrollPane leftScroll;  
  47.     private JSplitPane centerSplit;  
  48.   
  49.     private DefaultListModel listModel;  
  50.     private boolean isConnected = false;  
  51.   
  52.     private Socket socket;  
  53.     private PrintWriter writer;  
  54.     private BufferedReader reader;  
  55.     private MessageThread messageThread;// 負責接收消息的線程  
  56.     private Map<String, User> onLineUsers = new HashMap<String, User>();// 全部在線用戶  
  57.   
  58.     // 主方法,程序入口  
  59.     public static void main(String[] args) {  
  60.         new Client();  
  61.     }  
  62.   
  63.     // 執行發送  
  64.     public void send() {  
  65.         if (!isConnected) {  
  66.             JOptionPane.showMessageDialog(frame, "尚未鏈接服務器,沒法發送消息!", "錯誤",  
  67.                     JOptionPane.ERROR_MESSAGE);  
  68.             return;  
  69.         }  
  70.         String message = textField.getText().trim();  
  71.         if (message == null || message.equals("")) {  
  72.             JOptionPane.showMessageDialog(frame, "消息不能爲空!", "錯誤",  
  73.                     JOptionPane.ERROR_MESSAGE);  
  74.             return;  
  75.         }  
  76.         sendMessage(frame.getTitle() + "@" + "ALL" + "@" + message);  
  77.         textField.setText(null);  
  78.     }  
  79.   
  80.     // 構造方法  
  81.     public Client() {  
  82.         textArea = new JTextArea();  
  83.         textArea.setEditable(false);  
  84.         textArea.setForeground(Color.blue);  
  85.         textField = new JTextField();  
  86.         txt_port = new JTextField("6666");  
  87.         txt_hostIp = new JTextField("127.0.0.1");  
  88.         txt_name = new JTextField("xiaoqiang");  
  89.         btn_start = new JButton("鏈接");  
  90.         btn_stop = new JButton("斷開");  
  91.         btn_send = new JButton("發送");  
  92.         listModel = new DefaultListModel();  
  93.         userList = new JList(listModel);  
  94.   
  95.         northPanel = new JPanel();  
  96.         northPanel.setLayout(new GridLayout(1, 7));  
  97.         northPanel.add(new JLabel("端口"));  
  98.         northPanel.add(txt_port);  
  99.         northPanel.add(new JLabel("服務器IP"));  
  100.         northPanel.add(txt_hostIp);  
  101.         northPanel.add(new JLabel("姓名"));  
  102.         northPanel.add(txt_name);  
  103.         northPanel.add(btn_start);  
  104.         northPanel.add(btn_stop);  
  105.         northPanel.setBorder(new TitledBorder("鏈接信息"));  
  106.   
  107.         rightScroll = new JScrollPane(textArea);  
  108.         rightScroll.setBorder(new TitledBorder("消息顯示區"));  
  109.         leftScroll = new JScrollPane(userList);  
  110.         leftScroll.setBorder(new TitledBorder("在線用戶"));  
  111.         southPanel = new JPanel(new BorderLayout());  
  112.         southPanel.add(textField, "Center");  
  113.         southPanel.add(btn_send, "East");  
  114.         southPanel.setBorder(new TitledBorder("寫消息"));  
  115.   
  116.         centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScroll,  
  117.                 rightScroll);  
  118.         centerSplit.setDividerLocation(100);  
  119.   
  120.         frame = new JFrame("客戶機");  
  121.         // 更改JFrame的圖標:  
  122.         frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));  
  123.         frame.setLayout(new BorderLayout());  
  124.         frame.add(northPanel, "North");  
  125.         frame.add(centerSplit, "Center");  
  126.         frame.add(southPanel, "South");  
  127.         frame.setSize(600, 400);  
  128.         int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;  
  129.         int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;  
  130.         frame.setLocation((screen_width - frame.getWidth()) / 2,  
  131.                 (screen_height - frame.getHeight()) / 2);  
  132.         frame.setVisible(true);  
  133.   
  134.         // 寫消息的文本框中按回車鍵時事件  
  135.         textField.addActionListener(new ActionListener() {  
  136.             public void actionPerformed(ActionEvent arg0) {  
  137.                 send();  
  138.             }  
  139.         });  
  140.   
  141.         // 單擊發送按鈕時事件  
  142.         btn_send.addActionListener(new ActionListener() {  
  143.             public void actionPerformed(ActionEvent e) {  
  144.                 send();  
  145.             }  
  146.         });  
  147.   
  148.         // 單擊鏈接按鈕時事件  
  149.         btn_start.addActionListener(new ActionListener() {  
  150.             public void actionPerformed(ActionEvent e) {  
  151.                 int port;  
  152.                 if (isConnected) {  
  153.                     JOptionPane.showMessageDialog(frame, "已處於鏈接上狀態,不要重複鏈接!",  
  154.                             "錯誤", JOptionPane.ERROR_MESSAGE);  
  155.                     return;  
  156.                 }  
  157.                 try {  
  158.                     try {  
  159.                         port = Integer.parseInt(txt_port.getText().trim());  
  160.                     } catch (NumberFormatException e2) {  
  161.                         throw new Exception("端口號不符合要求!端口爲整數!");  
  162.                     }  
  163.                     String hostIp = txt_hostIp.getText().trim();  
  164.                     String name = txt_name.getText().trim();  
  165.                     if (name.equals("") || hostIp.equals("")) {  
  166.                         throw new Exception("姓名、服務器IP不能爲空!");  
  167.                     }  
  168.                     boolean flag = connectServer(port, hostIp, name);  
  169.                     if (flag == false) {  
  170.                         throw new Exception("與服務器鏈接失敗!");  
  171.                     }  
  172.                     frame.setTitle(name);  
  173.                     JOptionPane.showMessageDialog(frame, "成功鏈接!");  
  174.                 } catch (Exception exc) {  
  175.                     JOptionPane.showMessageDialog(frame, exc.getMessage(),  
  176.                             "錯誤", JOptionPane.ERROR_MESSAGE);  
  177.                 }  
  178.             }  
  179.         });  
  180.   
  181.         // 單擊斷開按鈕時事件  
  182.         btn_stop.addActionListener(new ActionListener() {  
  183.             public void actionPerformed(ActionEvent e) {  
  184.                 if (!isConnected) {  
  185.                     JOptionPane.showMessageDialog(frame, "已處於斷開狀態,不要重複斷開!",  
  186.                             "錯誤", JOptionPane.ERROR_MESSAGE);  
  187.                     return;  
  188.                 }  
  189.                 try {  
  190.                     boolean flag = closeConnection();// 斷開鏈接  
  191.                     if (flag == false) {  
  192.                         throw new Exception("斷開鏈接發生異常!");  
  193.                     }  
  194.                     JOptionPane.showMessageDialog(frame, "成功斷開!");  
  195.                 } catch (Exception exc) {  
  196.                     JOptionPane.showMessageDialog(frame, exc.getMessage(),  
  197.                             "錯誤", JOptionPane.ERROR_MESSAGE);  
  198.                 }  
  199.             }  
  200.         });  
  201.   
  202.         // 關閉窗口時事件  
  203.         frame.addWindowListener(new WindowAdapter() {  
  204.             public void windowClosing(WindowEvent e) {  
  205.                 if (isConnected) {  
  206.                     closeConnection();// 關閉鏈接  
  207.                 }  
  208.                 System.exit(0);// 退出程序  
  209.             }  
  210.         });  
  211.     }  
  212.   
  213.     /**  
  214.      * 鏈接服務器  
  215.      *   
  216.      * @param port  
  217.      * @param hostIp  
  218.      * @param name  
  219.      */  
  220.     public boolean connectServer(int port, String hostIp, String name) {  
  221.         // 鏈接服務器  
  222.         try {  
  223.             socket = new Socket(hostIp, port);// 根據端口號和服務器ip創建鏈接  
  224.             writer = new PrintWriter(socket.getOutputStream());  
  225.             reader = new BufferedReader(new InputStreamReader(socket  
  226.                     .getInputStream()));  
  227.             // 發送客戶端用戶基本信息(用戶名和ip地址)  
  228.             sendMessage(name + "@" + socket.getLocalAddress().toString());  
  229.             // 開啓接收消息的線程  
  230.             messageThread = new MessageThread(reader, textArea);  
  231.             messageThread.start();  
  232.             isConnected = true;// 已經鏈接上了  
  233.             return true;  
  234.         } catch (Exception e) {  
  235.             textArea.append("與端口號爲:" + port + "    IP地址爲:" + hostIp  
  236.                     + "   的服務器鏈接失敗!" + "\r\n");  
  237.             isConnected = false;// 未鏈接上  
  238.             return false;  
  239.         }  
  240.     }  
  241.   
  242.     /**  
  243.      * 發送消息  
  244.      *   
  245.      * @param message  
  246.      */  
  247.     public void sendMessage(String message) {  
  248.         writer.println(message);  
  249.         writer.flush();  
  250.     }  
  251.   
  252.     /**  
  253.      * 客戶端主動關閉鏈接  
  254.      */  
  255.     @SuppressWarnings("deprecation")  
  256.     public synchronized boolean closeConnection() {  
  257.         try {  
  258.             sendMessage("CLOSE");// 發送斷開鏈接命令給服務器  
  259.             messageThread.stop();// 中止接受消息線程  
  260.             // 釋放資源  
  261.             if (reader != null) {  
  262.                 reader.close();  
  263.             }  
  264.             if (writer != null) {  
  265.                 writer.close();  
  266.             }  
  267.             if (socket != null) {  
  268.                 socket.close();  
  269.             }  
  270.             isConnected = false;  
  271.             return true;  
  272.         } catch (IOException e1) {  
  273.             e1.printStackTrace();  
  274.             isConnected = true;  
  275.             return false;  
  276.         }  
  277.     }  
  278.   
  279.     // 不斷接收消息的線程  
  280.     class MessageThread extends Thread {  
  281.         private BufferedReader reader;  
  282.         private JTextArea textArea;  
  283.   
  284.         // 接收消息線程的構造方法  
  285.         public MessageThread(BufferedReader reader, JTextArea textArea) {  
  286.             this.reader = reader;  
  287.             this.textArea = textArea;  
  288.         }  
  289.   
  290.         // 被動的關閉鏈接  
  291.         public synchronized void closeCon() throws Exception {  
  292.             // 清空用戶列表  
  293.             listModel.removeAllElements();  
  294.             // 被動的關閉鏈接釋放資源  
  295.             if (reader != null) {  
  296.                 reader.close();  
  297.             }  
  298.             if (writer != null) {  
  299.                 writer.close();  
  300.             }  
  301.             if (socket != null) {  
  302.                 socket.close();  
  303.             }  
  304.             isConnected = false;// 修改狀態爲斷開  
  305.         }  
  306.   
  307.         public void run() {  
  308.             String message = "";  
  309.             while (true) {  
  310.                 try {  
  311.                     message = reader.readLine();  
  312.                     StringTokenizer stringTokenizer = new StringTokenizer(  
  313.                             message, "/@");  
  314.                     String command = stringTokenizer.nextToken();// 命令  
  315.                     if (command.equals("CLOSE"))// 服務器已關閉命令  
  316.                     {  
  317.                         textArea.append("服務器已關閉!\r\n");  
  318.                         closeCon();// 被動的關閉鏈接  
  319.                         return;// 結束線程  
  320.                     } else if (command.equals("ADD")) {// 有用戶上線更新在線列表  
  321.                         String username = "";  
  322.                         String userIp = "";  
  323.                         if ((username = stringTokenizer.nextToken()) != null  
  324.                                 && (userIp = stringTokenizer.nextToken()) != null) {  
  325.                             User user = new User(username, userIp);  
  326.                             onLineUsers.put(username, user);  
  327.                             listModel.addElement(username);  
  328.                         }  
  329.                     } else if (command.equals("DELETE")) {// 有用戶下線更新在線列表  
  330.                         String username = stringTokenizer.nextToken();  
  331.                         User user = (User) onLineUsers.get(username);  
  332.                         onLineUsers.remove(user);  
  333.                         listModel.removeElement(username);  
  334.                     } else if (command.equals("USERLIST")) {// 加載在線用戶列表  
  335.                         int size = Integer  
  336.                                 .parseInt(stringTokenizer.nextToken());  
  337.                         String username = null;  
  338.                         String userIp = null;  
  339.                         for (int i = 0; i < size; i++) {  
  340.                             username = stringTokenizer.nextToken();  
  341.                             userIp = stringTokenizer.nextToken();  
  342.                             User user = new User(username, userIp);  
  343.                             onLineUsers.put(username, user);  
  344.                             listModel.addElement(username);  
  345.                         }  
  346.                     } else if (command.equals("MAX")) {// 人數已達上限  
  347.                         textArea.append(stringTokenizer.nextToken()  
  348.                                 + stringTokenizer.nextToken() + "\r\n");  
  349.                         closeCon();// 被動的關閉鏈接  
  350.                         JOptionPane.showMessageDialog(frame, "服務器緩衝區已滿!", "錯誤",  
  351.                                 JOptionPane.ERROR_MESSAGE);  
  352.                         return;// 結束線程  
  353.                     } else {// 普通消息  
  354.                         textArea.append(message + "\r\n");  
  355.                     }  
  356.                 } catch (IOException e) {  
  357.                     e.printStackTrace();  
  358.                 } catch (Exception e) {  
  359.                     e.printStackTrace();  
  360.                 }  
  361.             }  
  362.         }  
  363.     }  
  364. }  


 

 

User.java

[html] view plain copy

 

  1. //用戶信息類  
  2. public class User{  
  3.     private String name;  
  4.     private String ip;  
  5.   
  6.     public User(String name, String ip) {  
  7.         this.name = name;  
  8.         this.ip = ip;  
  9.     }  
  10.   
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.   
  15.     public void setName(String name) {  
  16.         this.name = name;  
  17.     }  
  18.   
  19.     public String getIp() {  
  20.         return ip;  
  21.     }  
  22.   
  23.     public void setIp(String ip) {  
  24.         this.ip = ip;  
  25.     }  
  26. }  


 

注: 在eclipse下運行無需另外添加jar文件,其中服務器端和客戶端均須要一張圖片作icon,你們能夠隨便找張圖片補上。 接把圖片放在所建的包下,和三個類文件並列放在一塊兒就行

 

Java Socket   多人聊天室 swing 局域網

相關文章
相關標籤/搜索