Liny_@NotePad

沉迷ACG中

点对点聊天系统 v1.0

YOYO posted @ 2008年9月11日 08:22 in 【Java SE】 with tags 网络编程 im , 3485 阅读

【系统需求】

聊天交流是目前互联网提供的主要内容。聊天系统有多种实现方式,类似ICQ属于一种点对点的聊天系统,还有一种是基于Socket的集中式聊天系统,这种聊天系统需要登录统一的聊天服务器,每个人的聊天信息其他人都可以看到,类似一种会议室,当然,两个人之间也可以进行保密的私语。

在基于Socket的聊天系统中,主要有两种角色:服务器和客户端,不同的客户端登录集中式的服务器,通过服务器将一个客户端发出的信息推送到其他所有客户端。

【基本功能要求】

 · 必须能够支持两个客户端一起聊天。
 · 客户端和服务器必须保持随时随地的连接,一个客户端发出聊天信息的同时,另一个客户端接受发送过来的聊天信息。

【目标】

 · 熟悉使用网络编程,socket编程
 · 熟悉使用多线程编程
 · 复习Swing图形化设计

【程序说明】

本程序应许多个客户端连接服务器进行聊天。
客户端发送信息给服务器,服务器接收信息并通知给所有已连接上的客户端。

【运行截图】

【源码】

服务器端:Server.java

  1. import java.util.*;
  2. import java.io.*;
  3. import java.net.*;
  4.  
  5. /**
  6. * 服务端
  7. * @author Linyq.
  8. * @author YOYO.1989x.net
  9. * @version 1.0
  10. */
  11. public class Server{
  12.  
  13.         /**
  14.          * 服务器使用的端口
  15.          */
  16.         int port = 1989;
  17.        
  18.         /**
  19.          * 连接中的客户端列表
  20.          */
  21.         List<UpdateClient> ClientList = new ArrayList<UpdateClient>();
  22.        
  23.         /**
  24.          * 入口方法
  25.          * @param args
  26.          */
  27.         public static void main(String[] args){
  28.                 new Server();
  29.         }
  30.        
  31.         /**
  32.          * 构造方法
  33.          */
  34.         public Server(){
  35.                 try {
  36.                         ServerSocket serverSocket = new ServerSocket(port);
  37.                         while(true){
  38.                                 Socket socket = serverSocket.accept();
  39.                                 UpdateClient Client = new UpdateClient(socket);
  40.                                 new Thread(Client).start();
  41.                                 ClientList.add(Client);
  42.                         }
  43.                 } catch(BindException be){
  44.                         System.out.println(port + "端口被占用,请关闭其他程序再尝试。");
  45.                 }
  46.                 catch (IOException e) {
  47.                         e.printStackTrace();
  48.                 }
  49.         }
  50.        
  51.         /**
  52.          * 接收/发送客户端信息的线程类。
  53.          * @author Linyq.
  54.          * @author YOYO.1989x.net
  55.          * @version 1.0
  56.          */
  57.         private class UpdateClient implements Runnable {
  58.                
  59.                 /**
  60.                  * 客户端Socket
  61.                  */
  62.                 private Socket socket = null;
  63.                
  64.                 /**
  65.                  * 数据输出流
  66.                  */
  67.                 private DataOutputStream dos;
  68.                
  69.                 /**
  70.                  * 数据输入流
  71.                  */
  72.                 private DataInputStream dis;
  73.                
  74.                 /**
  75.                  * 构造方法:创建一个指定Socket的客户端更新类对象
  76.                  * @param socket 客户端Socket
  77.                  */
  78.                 public UpdateClient(Socket socket){
  79.                         this.socket = socket;
  80.                         try {
  81.                                 dos = new DataOutputStream(socket.getOutputStream());
  82.                                 dis = new DataInputStream(socket.getInputStream());
  83.                         } catch (IOException e) {
  84.                         }
  85.                 }
  86.                
  87.                 /**
  88.                  * 向客户端发送信息
  89.                  * @param content 信息
  90.                  */
  91.                 private void update(String content){
  92.                         try {
  93.                                 dos.writeUTF(content);
  94.                         } catch (IOException e) {
  95.                                 ClientList.remove(socket);
  96.                         }
  97.                 }
  98.  
  99.                 /**
  100.                  * 接收客户端信息并向所有已连接上客户端发送信息
  101.                  */
  102.                 public void run(){
  103.                         try {
  104.                                 while(true){
  105.                                         String content = dis.readUTF();
  106.                                         System.out.println(content);
  107.                                         for(UpdateClient Client: ClientList){
  108.                                                 Client.update(content);
  109.                                         }
  110.                                 }
  111.                         } catch (IOException e) {
  112.                         }       
  113.                 }
  114.                
  115.         }
  116.  
  117. }
  118.  

 

客户端:Client.java

  1. import java.io.*;
  2. import java.net.*;
  3. import javax.swing.*;
  4.  
  5. import java.awt.*;
  6. import java.awt.event.*;
  7. import java.io.*;
  8. import java.util.Date;
  9.  
  10. import javax.swing.*;
  11.  
  12. /**
  13. * 客户端
  14. * @author Linyq.
  15. * @author YOYO.1989x.net
  16. * @version 1.0
  17. */
  18.  
  19. public class Client extends JFrame{
  20.        
  21.         /**
  22.          * 聊天内容显示区域
  23.          */
  24.         JTextArea chatArea = new JTextArea(8,30);
  25.         /**
  26.          * 聊天内容滚动条框架
  27.          */
  28.         JScrollPane chatPane = new JScrollPane(chatArea);
  29.        
  30.         /**
  31.          * 发送区域
  32.          */
  33.         JPanel submitPanel = new JPanel();
  34.         /**
  35.          * 名字输入框
  36.          */
  37.         JTextField nameText = new JTextField("yahreso",6);
  38.         /**
  39.          * 信息输入框
  40.          */
  41.         JTextField contentText = new JTextField(30);
  42.        
  43.         /**
  44.          * 服务器Socket
  45.          */
  46.         Socket server = null;
  47.         /**
  48.          * 服务器数据输出流
  49.          */
  50.         DataOutputStream dos = null;
  51.         /**
  52.          * 服务器数据输入流
  53.          */
  54.         DataInputStream dis = null;
  55.         /**
  56.          * 服务器IP地址
  57.          */
  58.         String ip = "127.0.0.1";
  59.         /**
  60.          * 服务器端口号
  61.          */
  62.         int port = 1989;
  63.        
  64.         /**
  65.          * 接收服务器信息线程
  66.          */
  67.         Thread serverThread = new Thread(new UpdateContent());
  68.        
  69.         /**
  70.          * 构造窗体
  71.          */
  72.         public Client(){
  73.                 init();
  74.                 connect();
  75.                 serverThread.start();
  76.         }
  77.        
  78.         /**
  79.          * 初始化窗口信息
  80.          */
  81.         private void init(){
  82.                 this.setTitle("点对点聊天系统");
  83.                 this.setSize(430,220);
  84.                 this.setResizable(false);
  85.                 this.setLayout(new BorderLayout());
  86.                
  87.                 chatArea.setEditable(false);
  88.                 this.add(chatPane,"Center");
  89.                
  90.                 submitPanel.setSize(500,80);
  91.                 submitPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
  92.                 submitPanel.add(nameText);
  93.                 submitPanel.add(contentText);
  94.                
  95.                 this.add(submitPanel,"South");
  96.  
  97. //            contentText.addKeyListener(new EnterListener());
  98.                 contentText.addActionListener(new EnterListener());
  99.                
  100.                 this.addWindowListener(new CloseWindowListener());
  101.                
  102.                 this.setVisible(true);
  103.         }
  104.        
  105.         /**
  106.          * 按下回车键触发的监听器
  107.          * @author Linyq.
  108.          * @author YOYO.1989x.net
  109.          * @version 1.0
  110.          */
  111.         private class EnterListener implements ActionListener{
  112.  
  113.                 @Override
  114.                 public void actionPerformed(ActionEvent e) {
  115.                         String nowTime = new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds();
  116.                         sendContent(nameText.getText() + ": " + contentText.getText() + " ["+ nowTime + "]");
  117.                         contentText.setText(null);
  118.                 }
  119.                
  120.         }
  121. //      private class EnterListener implements KeyListener{
  122. //
  123. //            /**
  124. //             * 按下回车键后发送信息
  125. //             * @param e 键盘事件
  126. //             */
  127. //            public void keyPressed(KeyEvent e) {
  128. //                  if(e.getKeyCode()==KeyEvent.VK_ENTER){
  129. //                        String nowTime = new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds();
  130. //                        sendContent(nameText.getText() + ": " + contentText.getText() + " ["+ nowTime + "]");
  131. //                        contentText.setText(null);
  132. //                  }     
  133. //            }
  134. //
  135. //            public void keyReleased(KeyEvent e) {   
  136. //            }
  137. //
  138. //            public void keyTyped(KeyEvent e) {       
  139. //            }
  140. //           
  141. //      }
  142.        
  143.         /**
  144.          * 关闭窗口触发的监听器
  145.          * @author Linyq.
  146.          * @author YOYO.1989x.net
  147.          * @version 1.0
  148.          */
  149.         private class CloseWindowListener implements WindowListener{
  150.  
  151.                 public void windowActivated(WindowEvent e) {
  152.                 }
  153.  
  154.                 public void windowClosed(WindowEvent e) {
  155.                 }
  156.  
  157.                 public void windowClosing(WindowEvent e) {
  158.                         sendContent(nameText.getText() + " 退出了聊天室。");
  159.                         disconnect();
  160.                 }
  161.  
  162.                 public void windowDeactivated(WindowEvent e) {
  163.                 }
  164.  
  165.                 public void windowDeiconified(WindowEvent e) {
  166.                 }
  167.  
  168.                 public void windowIconified(WindowEvent e) {
  169.                 }
  170.  
  171.                 public void windowOpened(WindowEvent e) {
  172.                 }
  173.                
  174.         }
  175.        
  176.         /**
  177.          * 更新聊天内容
  178.          * @param content 信息
  179.          */
  180.         private void updateContent(String content){
  181.                 chatArea.append("\n"+content);
  182.                 chatArea.selectAll();
  183.         }
  184.        
  185.         /**
  186.          * 连接服务器
  187.          */
  188.         private void connect(){
  189.                 try {
  190.                         server = new Socket(ip,port);
  191.                         dos = new DataOutputStream(server.getOutputStream());
  192.                         dis = new DataInputStream(server.getInputStream());
  193.                         updateContent("已连接上服务器..");
  194.                         sendContent(nameText.getText() + "进入聊天室。");
  195.                 } catch (UnknownHostException e) {
  196.                         updateContent("服务器未启动。");
  197.                 } catch (IOException e) {
  198.                         updateContent("找不到服务器。");
  199.                 }
  200.         }
  201.        
  202.         /**
  203.          * 断开连接
  204.          */
  205.         private void disconnect(){
  206.                 try {
  207.                         dos.close();
  208.                         dis.close();
  209.                         server.close();
  210.                 } catch (IOException e) {
  211.                         updateContent("找不到服务器。");
  212.                 }
  213.         }
  214.        
  215.         /**
  216.          * 向服务器端发送信息
  217.          * @param content 信息
  218.          */
  219.         private void sendContent(String content){
  220.                 try {
  221.                         dos.writeUTF(content);
  222.                         dos.flush();
  223.                 } catch (IOException e) {
  224.                         updateContent("找不到服务器。");
  225.                 }
  226.         }
  227.        
  228.         /**
  229.          * 接收服务器端信息
  230.          * @author Linyq.
  231.          * @author YOYO.1989x.net
  232.          * @version 1.0
  233.          */
  234.         private class UpdateContent implements Runnable{
  235.  
  236.                 /**
  237.                  * 重载run方法,接收服务器信息并更新聊天内容
  238.                  */
  239.                 public void run() {
  240.                         try {
  241.                                 while(true){
  242.                                         String content = dis.readUTF();
  243.                                         updateContent(content);
  244.                                 }       
  245.                         } catch (IOException e) {
  246.                                 updateContent("找不到服务器。");
  247.                         }
  248.                        
  249.                 }
  250.                
  251.         }
  252.        
  253.         /**
  254.          * 入口方法
  255.          * @param args
  256.          */
  257.         public static void main(String[] args){
  258.                 JFrame.setDefaultLookAndFeelDecorated(true);   
  259.                 new Client();   
  260.         }
  261.        
  262. }

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter