java 通过TCPUDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端

Posted alm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 通过TCPUDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端相关的知识,希望对你有一定的参考价值。

java 通过TCP\\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端

 

  启动界面如下图:

 

 

 

首先启动服务器:

 

 

客户端登陆,登陆成功后为:

 

默认发送是全部用户,是多人发送。  当在边列表里面选择了用户后,可以与此用户建立点对点链接进行聊天,可以发送文件。

 

 

 

 用户在线离线状态会实时更新,如果离线,则存为离线消息。当下次上线的时候,会接受到离线消息

 

 

 

 

 从一个用户接受文件的同时,还可以接受从服务器发过来的文件

 

接受文件完成后,显示记录,并显示保存目录

 

消息发送演示

 

 服务器端代码:

   1 import sun.misc.BASE64Encoder;
   2 
   3 import java.awt.BorderLayout;
   4 import java.awt.Color;
   5 import java.awt.GridLayout;
   6 import java.awt.Toolkit;
   7 import java.awt.event.ActionEvent;
   8 import java.awt.event.ActionListener;
   9 import java.awt.event.WindowAdapter;
  10 import java.awt.event.WindowEvent;
  11 import java.io.*;
  12 import java.net.BindException;
  13 import java.net.ServerSocket;
  14 import java.net.Socket;
  15 import java.security.MessageDigest;
  16 import java.security.NoSuchAlgorithmException;
  17 import java.sql.Connection;
  18 import java.sql.DriverManager;
  19 import java.sql.ResultSet;
  20 import java.sql.Statement;
  21 import java.text.SimpleDateFormat;
  22 import java.util.ArrayList;
  23 import java.util.Date;
  24 import java.util.StringTokenizer;
  25 
  26 import javax.swing.DefaultListModel;
  27 import javax.swing.JButton;
  28 import javax.swing.JFileChooser;
  29 import javax.swing.JFrame;
  30 import javax.swing.JLabel;
  31 import javax.swing.JList;
  32 import javax.swing.JOptionPane;
  33 import javax.swing.JPanel;
  34 import javax.swing.JScrollPane;
  35 import javax.swing.JSplitPane;
  36 import javax.swing.JTextArea;
  37 import javax.swing.JTextField;
  38 import javax.swing.border.TitledBorder;
  39 import javax.swing.event.ListSelectionEvent;
  40 import javax.swing.event.ListSelectionListener;
  41 
  42 public class Server {
  43 
  44     private JFrame frame;
  45     private JTextArea contentArea;
  46     private JTextField txt_message;
  47     private JTextField txt_max;
  48     private JTextField txt_port;
  49     private JButton btn_start;
  50     private JButton btn_stop;
  51     private JButton btn_send;
  52     private JButton btn_send_file;
  53     private JPanel northPanel;
  54     private JPanel southPanel;
  55     private JPanel sendPanel;
  56     private JScrollPane rightPanel;
  57     private JScrollPane leftPanel;
  58     private JScrollPane rightPanel2;
  59     private JSplitPane centerSplit;
  60     private JSplitPane centerSplit2;
  61     private JList userList;
  62     private JList all_userList;
  63     private DefaultListModel listModel;
  64     private static DefaultListModel all_listModel;
  65 
  66     private ServerSocket serverSocket;
  67     private ServerThread serverThread;
  68     private ArrayList<ClientThread> clients;//客户线程数组
  69 
  70     private boolean isStart = false;//标志服务器是否启动或关闭
  71 
  72     private int sendfor_who = 0;//监听左边jlist,保存给哪个用户发消息
  73 
  74     // 主方法,程序执行入口
  75     public static void main(String[] args) {
  76 
  77         new Server();
  78 
  79         try {
  80             Connection con = null; //定义一个mysql链接对象
  81             Class.forName("com.mysql.jdbc.Driver").newInstance();//MYSQL驱动
  82             con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/server_db", "root", "root"); //链接本地MYSQL
  83             Statement stmt; //创建声明
  84             stmt = con.createStatement();
  85 
  86         } catch (Exception e) {
  87             System.out.print("MYSQL ERROR:" + e.getMessage());
  88         }
  89     }
  90 
  91     /**利用MD5进行加密
  92      * @param str  待加密的字符串
  93      * @return  加密后的字符串
  94      * @throws NoSuchAlgorithmException  没有这种产生消息摘要的算法
  95      * @throws UnsupportedEncodingException
  96      */
  97     public String EncoderByMd5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
  98         //确定计算方法
  99         MessageDigest md5=MessageDigest.getInstance("MD5");
 100         BASE64Encoder base64en = new BASE64Encoder();
 101         //加密后的字符串
 102         String newstr=base64en.encode(md5.digest(str.getBytes("utf-8")));
 103         return newstr;
 104     }
 105 
 106     /**判断用户密码是否正确
 107      * @param newpasswd  用户输入的密码
 108      * @param oldpasswd  数据库中存储的密码--用户密码的摘要
 109      * @return
 110      * @throws NoSuchAlgorithmException
 111      * @throws UnsupportedEncodingException
 112      */
 113     public boolean checkpassword(String newpasswd,String oldpasswd) throws NoSuchAlgorithmException, UnsupportedEncodingException{
 114         if(EncoderByMd5(newpasswd).equals(oldpasswd))
 115             return true;
 116         else
 117             return false;
 118     }
 119 
 120     /**
 121      * 刚服务器突然关闭时,把所有用户状态置为离线
 122      */
 123     public void set_user_state_off() {
 124         try {
 125             Connection con = null; //定义一个MYSQL链接对象
 126             Class.forName("com.mysql.jdbc.Driver").newInstance();//MYSQL驱动
 127             con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/server_db", "root", "root"); //链接本地MYSQL
 128             Statement stmt; //创建声明
 129             stmt = con.createStatement();
 130 
 131             int id = 0;
 132             String selectSql = "UPDATE user SET state = 0";
 133             stmt.executeUpdate(selectSql);
 134         } catch (Exception e) {
 135             System.out.print("MYSQL ERROR:" + e.getMessage());
 136         }
 137     }
 138 
 139     /**
 140      * 更新用户状态
 141      */
 142     public void user_name_update() {
 143 
 144         try {
 145             Connection con = null; //定义一个MYSQL链接对象
 146             Class.forName("com.mysql.jdbc.Driver").newInstance();//MYSQL驱动
 147             con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/server_db", "root", "root"); //链接本地MYSQL
 148             Statement stmt; //创建声明
 149             stmt = con.createStatement();
 150 
 151             all_listModel.removeAllElements();
 152             all_listModel.addElement("全部用户");
 153 
 154             String username_db;
 155             int state = 0;
 156             //查询用户名
 157             String selectSql = "SELECT * FROM user";
 158             ResultSet selectRes = stmt.executeQuery(selectSql);
 159             while (selectRes.next()) { //循环输出结果集
 160                 username_db = selectRes.getString("username");
 161                 state = selectRes.getInt("state");
 162                 if (state == 1) {
 163                     all_listModel.addElement(username_db + "---(在线)");
 164                 }
 165 
 166             }
 167 
 168             selectRes = stmt.executeQuery(selectSql);
 169             while (selectRes.next()) { //循环输出结果集
 170                 username_db = selectRes.getString("username");
 171                 state = selectRes.getInt("state");
 172                 if (state == 0) {
 173                     all_listModel.addElement(username_db + "---(离线)");
 174                 }
 175 
 176             }
 177         } catch (Exception e) {
 178             System.out.print("MYSQL ERROR:" + e.getMessage());
 179         }
 180 
 181     }
 182 
 183     /**
 184      * 执行消息发送
 185      */
 186     public void send() {
 187         if (!isStart) {
 188             JOptionPane.showMessageDialog(frame, "服务器还未启动,不能发送消息!", "错误",
 189                     JOptionPane.ERROR_MESSAGE);
 190             return;
 191         }
 192 //        if (clients.size() == 0) {
 193 //            JOptionPane.showMessageDialog(frame, "没有用户在线,不能发送消息!", "错误",
 194 //                    JOptionPane.ERROR_MESSAGE);
 195 //            return;
 196 //        }
 197         String message = txt_message.getText().trim();
 198         if (message == null || message.equals("")) {
 199             JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误",
 200                     JOptionPane.ERROR_MESSAGE);
 201             return;
 202         }
 203         sendServerMessage(message, sendfor_who);// 群发服务器消息
 204         //contentArea.append("对  "+listModel.getElementAt(sendfor_who)+"  说:" + txt_message.getText() + "\\r\\n");
 205         txt_message.setText(null);
 206     }
 207 
 208     // 构造放法
 209     public Server() {
 210         SelecTry selectIndex = new SelecTry();
 211         frame = new JFrame("服务器");
 212         contentArea = new JTextArea();
 213         contentArea.setEditable(false);
 214         contentArea.setForeground(Color.blue);
 215         txt_message = new JTextField();
 216         txt_max = new JTextField("30");
 217         txt_port = new JTextField("6666");
 218         btn_start = new JButton("启动");
 219         btn_stop = new JButton("停止");
 220         btn_send = new JButton("发送");
 221         btn_send_file = new JButton("文件");
 222         btn_stop.setEnabled(false);
 223         listModel = new DefaultListModel();
 224         all_listModel = new DefaultListModel();
 225         //listModel.addElement("全部用户");
 226         userList = new JList(all_listModel);//listModel
 227         userList.addListSelectionListener(selectIndex);
 228 
 229         user_name_update();//更新用户状态
 230 
 231 //        all_userList = new JList(all_listModel);
 232 
 233         southPanel = new JPanel(new BorderLayout());
 234         sendPanel = new JPanel(new BorderLayout());
 235         southPanel.setBorder(new TitledBorder("写消息"));
 236         southPanel.add(txt_message, "Center");
 237         sendPanel.add(btn_send, BorderLayout.NORTH);
 238         sendPanel.add(btn_send_file, BorderLayout.SOUTH);
 239 
 240         southPanel.add(sendPanel, "East");
 241 
 242         leftPanel = new JScrollPane(userList);
 243         leftPanel.setBorder(new TitledBorder("用户列表"));
 244 
 245 //        rightPanel2 = new JScrollPane(all_userList);
 246 //        rightPanel2.setBorder(new TitledBorder("全部用户"));
 247 
 248         rightPanel = new JScrollPane(contentArea);
 249         rightPanel.setBorder(new TitledBorder("消息显示区"));
 250 
 251         centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,
 252                 rightPanel);
 253         centerSplit.setDividerLocation(150);
 254 
 255 //        centerSplit2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, centerSplit,
 256 //                rightPanel2);
 257 //        centerSplit2.setDividerLocation(450);
 258 
 259         northPanel = new JPanel();
 260         northPanel.setLayout(new GridLayout(1, 6));
 261         northPanel.add(new JLabel("          人数上限"));
 262         northPanel.add(txt_max);
 263         northPanel.add(new JLabel("           端口"));
 264         northPanel.add(txt_port);
 265         northPanel.add(btn_start);
 266         northPanel.add(btn_stop);
 267         northPanel.setBorder(new TitledBorder("配置信息"));
 268 
 269         frame.setLayout(new BorderLayout());
 270         frame.add(northPanel, "North");
 271         frame.add(centerSplit, "Center");
 272         //frame.add(rightPanel2,BorderLayout.EAST);
 273         frame.add(southPanel, "South");
 274         frame.setSize(600, 400);
 275         //frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//设置全屏
 276         int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;
 277         int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;
 278         frame.setLocation((screen_width - frame.getWidth()) / 2,
 279                 (screen_height - frame.getHeight()) / 2);
 280         frame.setVisible(true);
 281 
 282         // 关闭窗口时事件
 283         frame.addWindowListener(new WindowAdapter() {
 284             public void windowClosing(WindowEvent e) {
 285                 if (isStart) {
 286                     closeServer();// 关闭服务器
 287                 }
 288                 System.exit(0);// 退出程序
 289             }
 290         });
 291 
 292         // 文本框按回车键时事件
 293         txt_message.addActionListener(new ActionListener() {
 294             public void actionPerformed(ActionEvent e) {
 295                 send();
 296             }
 297         });
 298 
 299         // 单击发送按钮时事件
 300         btn_send.addActionListener(new ActionListener() {
 301             public void actionPerformed(ActionEvent arg0) {
 302                 send();
 303             }
 304         });
 305 
 306         //单机文件按钮时事件
 307         btn_send_file.addActionListener(new ActionListener() {
 308             public void actionPerformed(ActionEvent arg0) {
 309                 //文件选择对话框启动,当选择了文件以后给每一个client发送文件
 310                 JFileChooser sourceFileChooser = new JFileChooser(".");
 311                 sourceFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
 312                 int status = sourceFileChooser.showOpenDialog(frame);
 313                 File sourceFile = new File(sourceFileChooser.getSelectedFile().getPath());
 314                 //服务器text area提示
 315                 contentArea.append("发送文件:" + sourceFile.getName() + "\\r\\n");
 316                 for (int i = clients.size() - 1; i >= 0; i--) {
 317                     SendFileThread sendFile = new SendFileThread(frame, clients.get(i).socket, "服务器", sourceFileChooser, status);
 318                     sendFile.start();
 319                     //client端提示
 320                     clients.get(i).getWriter().println("服务器发送一个文件:" + sourceFile.getName() + "(多人发送)");
 321                     clients.get(i).getWriter().flush();
 322                 }
 323 
 324             }
 325         });
 326 
 327         // 单击启动服务器按钮时事件
 328         btn_start.addActionListener(new ActionListener() {
 329             public void actionPerformed(ActionEvent e) {
 330 
 331                 if (isStart) {
 332                     JOptionPane.showMessageDialog(frame, "服务器已处于启动状态,不要重复启动!",
 333                             "错误", JOptionPane.ERROR_MESSAGE);
 334                     return;
 335                 }
 336                 int max;//人数
 337                 int port;//端口号
 338                 try {
 339                     try {
 340                         max = Integer.parseInt(txt_max.getText());
 341                     } catch (Exception e1) {
 342                         throw new Exception("人数上限为正整数!");
 343                     }
 344                     if (max <= 0) {
 345                         throw new Exception("人数上限为正整数!");
 346                     }
 347                     try {
 348                         port = Integer.parseInt(txt_port.getText());
 349                     } catch (Exception e1) {
 350                         throw new Exception("端口号为正整数!");
 351                     }
 352                     if (port <= 0) {
 353                         throw new Exception("端口号 为正整数!");
 354                     }
 355                     serverStart(max, port);
 356                     contentArea.append("服务器已成功启动!   人数上限:" + max + ",  端口:" + port
 357                             + "\\r\\n");
 358                     JOptionPane.showMessageDialog(frame, "服务器成功启动!");
 359                     btn_start.setEnabled(false);
 360                     txt_max.setEnabled(false);
 361                     txt_port.setEnabled(false);
 362                     btn_stop.setEnabled(true);
 363                     listModel.addElement("全部用户");
 364                     user_name_update();
 365                 } catch (Exception exc) {
 366                     JOptionPane.showMessageDialog(frame, exc.getMessage(),
 367                             "错误", JOptionPane.ERROR_MESSAGE);
 368                 }
 369             }
 370         });
 371 
 372         // 单击停止服务器按钮时事件
 373         btn_stop.addActionListener(new ActionListener() {
 374             public void actionPerformed(ActionEvent e) {
 375                 if (!isStart) {
 376                     JOptionPane.showMessageDialog

以上是关于java 通过TCPUDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端的主要内容,如果未能解决你的问题,请参考以下文章

网络编程项目—— 多人聊天室->双人聊天

Java学习网络编程全总结——TCPUdp多线程IO流Socket简易在线咨询聊天室Java爬虫

java实现的多人聊天(控制台输入)

java是如何实现聊天功能的?

java中进行socket编程实现tcpudp协议总结

java中进行socket编程实现tcpudp协议总结