Java簡單聊天室


實現Java簡單的聊天室

  所用主要知識:多線程+網絡編程

    效果如下圖

 

 

/**
*
* @author Administrator
*
* 簡單的多人聊天系統——重點:同時性,異步性
* 1、客戶端:發送消息,並且接收消息
* 1.1 消息發送至服務器:服務器每次都將客戶發過來的信息發送到每個客戶端
* 1.2 接收消息:發送的同時也要接收消息,所以必須有兩個線程,一個發送消息,一個接收消息
* 1.3 關於這兩個線程:如果沒有線程,接收和發送就是按順序執行的了,那么是發送后接收還是接收后發送?或者是
* 一邊可以發送一邊又可以接收呢?答案不言而喻
* 1.4 在客戶端,用可以通過界面的點擊按鈕事件發送消息,所以就要開啟一個線程來接收服務器發送給客戶端的消息了
* 1.5 多線程:不需按步驟逐步循環,可以和其他程序同時執行,不相互干擾
* 2、服務器端:接收所有用戶的消息並且借每個用戶的消息發送給連接了服務器的客戶端
* 2.1 服務器既要接收C端信息又要想所有C端發送信息,先收后發。一收就發。
* 2.2 S端還要顯示C端上線提醒
* 2.3 上線提醒和收發信息是不影響的,互不干擾的,但是都要在S端上執行,如果沒有線程,所以的程序都要按順序執行了所以又要 多線程
* 2.4 一個線程負責向所以C端發送接收到的任何一條信息,一個線程負責顯示C端上線的信息
*
* 3、類:S端:Server、ServerFrame、sendThread 三個類
* C端:Client、ClientFrame 兩個類
*
*/

 

  1 package com.java.chat;
  2 
  3 import java.awt.event.ActionEvent;
  4 import java.awt.event.ActionListener;
  5 import java.io.BufferedReader;
  6 import java.io.BufferedWriter;
  7 import java.io.IOException;
  8 import java.io.InputStream;
  9 import java.io.InputStreamReader;
 10 import java.io.OutputStream;
 11 import java.io.OutputStreamWriter;
 12 import java.net.ServerSocket;
 13 import java.net.Socket;
 14 import java.util.ArrayList;
 15 import java.util.List;
 16 
 17 import javax.swing.JButton;
 18 import javax.swing.JFrame;
 19 import javax.swing.JTextArea;
 20 
 21 
 22 public class Server {
 23     //用於保存Socket的集合,也可以說是把個C端與S端的一個連接通道保存起來
 24     //作用:服務器將接收到的信息發給集合里的所以socket,也就是發給每個C端
 25     public static List<Socket> list = new ArrayList<Socket>();
 26 
 27     public static void main(String[] args) {
 28         new ServerFrame("服務器端");
 29     }
 30 
 31 }
 32 
 33 /*
 34  * 繼承Jframe類表示該類可以創建一個窗口程序了,
 35  * 實現ActionListener:動作監聽,在S端點擊“啟動服務器”是要執行的代碼
 36  * 實現Runnable:實現多線程,該窗口是個客戶端窗口,要開啟一個線程接收顯示服務器發過來的信息
 37  */
 38 class ServerFrame extends JFrame implements ActionListener, Runnable {
 39 
 40     private static final long serialVersionUID = 1L;
 41 
 42     private ServerSocket serverSocket = null;
 43 
 44     private Socket socket;
 45 
 46     private JButton start;
 47     private JTextArea message;
 48 
 49     public ServerFrame(String name) {
 50         super(name);
 51 
 52         start = new JButton("啟動服務器");
 53         start.addActionListener(this);
 54         message = new JTextArea();
 55         message.setEditable(false);
 56         this.add(start, "North");
 57         this.add(message, "Center");
 58 
 59         this.setResizable(false);
 60         this.setBounds(0, 0, 400, 300);
 61         this.setVisible(true);
 62         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 63     }
 64 
 65     @Override
 66     public void actionPerformed(ActionEvent e) {
 67         if (e.getSource() == start) {
 68             // 如果點擊的按鈕是開始按鈕。則啟動服務器。
 69             try {
 70                 serverSocket = new ServerSocket(6666);
 71                 message.setText("服務器已啟動。。。");
 72                 
 73                 //單擊“啟動服務器”開啟一個線程用於獲取用戶上線的情況
 74                 new Thread(this).start();
 75                 
 76             } catch (IOException e1) {
 77                 e1.printStackTrace();
 78             }
 79         }
 80     }
 81 
 82     //獲取C端上線的情況
 83     @Override
 84     public void run() {
 85         String address = null;
 86         int port = 0;
 87         //用一個死循環一直讓S端開啟接收C端的連接,將C端的IP和端口顯示在面板上
 88         //如果用循環的話就只能接收一次
 89         while (true) {
 90             try {
 91                 socket = serverSocket.accept();
 92                 Server.list.add(socket);
 93                 address = socket.getInetAddress().getHostAddress();
 94                 port = socket.getPort();
 95                 message.append("\r\nip/" + address + ":" + port + "\t上線了");
 96                 
 97                 //開啟轉發信息的線程
 98                 new sendThread(socket).start();
 99 
100             } catch (IOException e) {
101 //                System.out.println(address + ":" + port + "\t退出了服務器");
102             }
103         }
104     }
105 
106 }
107 
108 /*
109  * 接收每個C端的信息並向每個C端發送接收到的信息
110  */
111 class sendThread extends Thread {
112     private Socket socket;
113 
114     public sendThread(Socket socket) {
115         super();
116         this.socket = socket;
117     }
118 
119     @Override
120     public void run() {
121         InputStream is = null;
122         BufferedReader br = null;
123         String str = null;
124         OutputStream os = null;
125         BufferedWriter bw = null;
126         while (true) {
127             try {
128                 is = socket.getInputStream();
129                 br = new BufferedReader(new InputStreamReader(is));
130                 str = br.readLine();
131                 for (Socket s : Server.list) {
132                     os = s.getOutputStream();
133                     bw = new BufferedWriter(new OutputStreamWriter(os));
134                     bw.write(str);
135                     bw.newLine();
136                     bw.flush();
137                 }
138             } catch (IOException e) {
139                 //如果斷開連接則移除對於的socket
140                 Server.list.remove(socket);
141             }
142         }
143     }
144 }
服務器端代碼
  1 package com.java.chat;
  2 
  3 import java.awt.BorderLayout;
  4 import java.awt.Color;
  5 import java.awt.Font;
  6 import java.awt.event.ActionEvent;
  7 import java.awt.event.ActionListener;
  8 import java.io.BufferedReader;
  9 import java.io.BufferedWriter;
 10 import java.io.IOException;
 11 import java.io.InputStream;
 12 import java.io.InputStreamReader;
 13 import java.io.OutputStream;
 14 import java.io.OutputStreamWriter;
 15 import java.net.Socket;
 16 import java.text.SimpleDateFormat;
 17 import java.util.Date;
 18 
 19 import javax.swing.JButton;
 20 import javax.swing.JFrame;
 21 import javax.swing.JLabel;
 22 import javax.swing.JOptionPane;
 23 import javax.swing.JPanel;
 24 import javax.swing.JScrollPane;
 25 import javax.swing.JTextArea;
 26 import javax.swing.JTextField;
 27 
 28 /**
 29  * 
 30  * @author Administrator
 31  *
 32  */
 33 
 34 public class Client {
 35     public static void main(String[] args) {
 36         new ClientFrame("客戶端");
 37     }
 38 }
 39 
 40 /*
 41  * 繼承Jframe類表示該類可以創建一個窗口程序了,
 42  * 實現ActionListener:動作監聽,就是一個事件發送后應該執行什么就要重新它的方法
 43  * 實現Runnable:實現多線程,該窗口是個客戶端窗口,要開啟一個線程接收顯示服務器發過來的信息
 44  */
 45 class ClientFrame extends JFrame implements ActionListener, Runnable {
 46 
 47     private static final long serialVersionUID = 1L;
 48 
 49     private Socket socket;
 50     OutputStream os = null;
 51     BufferedWriter bw = null;
 52     
 53     JTextArea message;
 54     JScrollPane scroll;
 55     JTextField input;
 56     JButton submit;
 57     JPanel panel;
 58 
 59     String uname = "";
 60     // 聊天頁面
 61     JPanel chat;
 62 
 63     // 登錄頁面
 64     JPanel login;
 65     JTextField username;
 66     JButton ok;
 67 
 68     public ClientFrame(String name) {
 69         super(name);
 70     
 71         message = new JTextArea();
 72         message.setEditable(false);
 73         scroll = new JScrollPane(message);
 74         input = new JTextField(20);
 75         submit = new JButton("發送");
 76         panel = new JPanel();
 77 
 78         panel.add(input);
 79         panel.add(submit);
 80         chat = new JPanel(new BorderLayout());
 81         chat.add(scroll, "Center");
 82         chat.add(panel, "South");
 83         
 84         
 85         // 在創建客戶端窗體是就要把客戶端與服務端連接
 86         try {
 87             //127.0.0.1表示本機地址,地址好端口都可以改,這要看服務器那邊是什么地址和端口
 88             socket = new Socket("127.0.0.1", 6666);
 89             os = socket.getOutputStream();
 90             bw = new BufferedWriter(new OutputStreamWriter(os));
 91             
 92         } catch (IOException e1) {
 93             e1.printStackTrace();
 94         }
 95         
 96         /*    在創建C端窗體的時候也應該開啟一個線程接收顯示來自服務器的信息
 97          *     為什么要開啟一個線程呢?因為在這個窗體里既要實現消息的發送,
 98          *     也要接收信息,而且兩個不能按順序進行,也互不干擾,所以開啟一個線程時時刻刻等着S端發來的信息
 99          */
100         //接收信息
101         new Thread(this).start();
102         
103         //提交按鈕工作監聽器,點擊提交時觸發
104         submit.addActionListener(this);
105 
106         login = new JPanel();
107         username = new JTextField(20);
108         ok = new JButton("確定");
109         ok.addActionListener(this);
110         JLabel label = new JLabel("請輸入用戶名");
111         label.setFont(new Font(Font.DIALOG, Font.BOLD, 28));
112         label.setForeground(Color.red);
113         login.add(label);
114         login.add(username);
115         login.add(ok);
116 
117         this.add(chat);
118         this.add(login);
119 
120         this.setResizable(false);
121         this.setBounds(400, 100, 400, 300);
122         this.setVisible(true);
123         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
124     }
125 
126     @Override
127     public void actionPerformed(ActionEvent e) {
128         if (e.getSource() == submit) {
129             // 如果點擊提交按鈕,則表示需要將信息發送出去。
130             String str = null;
131             //以下三行是創建發送時間的代碼
132             Date date = new Date();
133             SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
134             String dateStr = format.format(date);
135             
136             str = uname+" "+dateStr+"  "+input.getText();
137             
138             try {
139                 bw.write(str);
140                 bw.newLine();
141 //                System.out.println("客戶端發送了:"+str);
142                 bw.flush();
143             } catch (IOException e1) {
144                 System.out.println("無法發送,服務器連接異常!");
145             }
146             
147 //            System.out.println(str);
148             
149         } else if (e.getSource() == ok) {// 用戶登錄
150             uname = username.getText();// 獲取文本框輸入的文本信息
151             if ("".equals(uname)) {
152                 JOptionPane.showMessageDialog(this, "用戶名不能為空!");
153             } else {
154                 login.setVisible(false);
155                 chat.setVisible(true);
156                 this.setTitle(uname + " 的客戶端");
157                 this.add(chat);
158             }
159         }
160     }
161 
162     //run方法里面的是接受S端信息和將信息顯示的代碼
163     @Override
164     public void run() {
165         BufferedReader br = null;
166         InputStream is = null;
167         String str = null;
168         try {
169             is = socket.getInputStream();
170             br = new BufferedReader(new InputStreamReader(is));
171             while (true) {
172                 str = br.readLine()+"\r\n";
173                 message.append(str);
174             }
175         } catch (IOException e) {
176             System.out.println("無法發送,服務器連接異常!");
177         }
178     }
179 
180 }
客戶端代碼

(完)


免責聲明!

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



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