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 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端的主要内容,如果未能解决你的问题,请参考以下文章