基于TCP协议的服务器中转简易聊天
项目比较简单:主要使用了TCP传输协议、多线程和swing窗口,以及IO流读写。
功能:各窗口之间简单的收发信息,另外附加一个抖动的效果。
服务器代码:
1 package com.java; 2 3 import java.awt.Dimension; 4 import java.awt.Toolkit; 5 import java.awt.event.ActionEvent; 6 import java.awt.event.ActionListener; 7 import java.awt.event.KeyAdapter; 8 import java.awt.event.KeyEvent; 9 import java.awt.event.KeyListener; 10 import java.io.BufferedReader; 11 import java.io.BufferedWriter; 12 import java.io.IOException; 13 import java.io.InputStreamReader; 14 import java.io.OutputStreamWriter; 15 import java.net.ServerSocket; 16 import java.net.Socket; 17 import java.util.Vector; 18 19 import javax.swing.JButton; 20 import javax.swing.JFrame; 21 import javax.swing.JOptionPane; 22 import javax.swing.JTextField; 23 24 public class Server extends JFrame { 25 Vector<Socket> v = new Vector<Socket>(); // 创建存放客户端连接套接字的集合 26 int port;// 端口号 27 JTextField jtf; // 设置为属性 方便写事件的时候使用 28 29 public Server() { // 设置服务器默认窗口 30 this.setTitle("基于TCP协议的服务器中转聊天"); 31 this.setSize(320, 100); 32 Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); 33 this.setLocation(d.width / 2 - getWidth() / 2, d.height / 2 - getHeight() / 2); 34 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 35 this.setLayout(null); 36 setAlwaysOnTop(true); 37 38 // 文本框 输入端口号 39 jtf = new JTextField(); 40 jtf.setColumns(10); 41 jtf.setBounds(10, 10, 80, 30); 42 jtf.addKeyListener(new KeyAdapter() { 43 public void keyPressed(KeyEvent e) { 44 char c = e.getKeyChar(); 45 if ('\n' == c) { 46 String s = jtf.getText(); 47 if (s.matches("[0-9]{4,6}")) { 48 port = new Integer(s); 49 setVisible(false); // 该设置要放在服务区启动之前 50 server(); 51 } else { 52 jtf.setText(""); 53 JOptionPane.showMessageDialog(null, "请输入4-6位的数字!"); 54 } 55 } 56 } 57 }); 58 this.add(jtf); 59 // 按钮 启动服务器(事件) 60 JButton jb = new JButton("启动服务器"); 61 jb.setBounds(180, 10, 100, 30); 62 jb.addActionListener(new ActionListener() { 63 public void actionPerformed(ActionEvent e) { 64 String s = jtf.getText(); 65 if (s.matches("[0-9]{4,6}")) { 66 port = new Integer(s); 67 setVisible(false); // 该设置要放在服务区启动之前 68 server(); 69 } else { 70 jtf.setText(""); 71 JOptionPane.showMessageDialog(null, "请输入4-6位的数字!"); 72 } 73 } 74 }); 75 this.add(jb); 76 } 77 78 public void server() { 79 // 创建服务器,病不停等待客户端连接,并将客户端连接存入集合 80 try { 81 ServerSocket s = new ServerSocket(port); 82 System.out.println("服务器已创建..."); 83 while (true) { 84 Socket c = s.accept();// 等待客户端响应 85 System.out.println("客户端+[" + c.getInetAddress() + "]已连接"); 86 v.add(c); // 将连接的客户端套接字放入集合,存放起来 87 // 启动转发线程 88 Transmit t = new Transmit(); // new一个线程实例 89 t.c = c; // 将连接的客户端套接字C传递给线程 90 t.start(); 91 } 92 } catch (IOException e) { 93 System.out.println("服务器启动出错"); 94 } 95 } 96 97 public class Transmit extends Thread { // 实现转发功能的线程 98 Socket c; 99 100 public void run() { 101 try { 102 BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); 103 while (true) { // 循环读取 104 String s = br.readLine(); 105 for (Socket c : v) { // 转发给其他所有已连接的线程 106 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(c.getOutputStream())); 107 bw.write(s + "\n"); 108 bw.flush(); 109 } 110 } 111 } catch (IOException e) { 112 System.out.println(c.getInetAddress() + "已退出"); 113 v.remove(c);// 不执行服务器会出现问题 要经常重启 114 } 115 } 116 } 117 118 public static void main(String[] args) { 119 new Server().setVisible(true); 120 } 121 }
客户端:
注:注册和登录没有实现对注册的账号和密码的判断(账号是否已经使用)。
1 package com.java; 2 3 import java.awt.BorderLayout; 4 import java.awt.Color; 5 import java.awt.Dimension; 6 import java.awt.Font; 7 import java.awt.Toolkit; 8 import java.awt.event.ActionEvent; 9 import java.awt.event.ActionListener; 10 import java.awt.event.KeyAdapter; 11 import java.awt.event.KeyEvent; 12 import java.awt.event.MouseAdapter; 13 import java.awt.event.MouseEvent; 14 import java.io.BufferedReader; 15 import java.io.BufferedWriter; 16 import java.io.FileInputStream; 17 import java.io.FileOutputStream; 18 import java.io.IOException; 19 import java.io.InputStreamReader; 20 import java.io.ObjectInputStream; 21 import java.io.ObjectOutputStream; 22 import java.io.OutputStreamWriter; 23 import java.net.Socket; 24 import java.text.SimpleDateFormat; 25 import java.util.Date; 26 import java.util.HashMap; 27 import java.util.Map; 28 import java.util.Set; 29 import javax.swing.JButton; 30 import javax.swing.JFrame; 31 import javax.swing.JLabel; 32 import javax.swing.JOptionPane; 33 import javax.swing.JPanel; 34 import javax.swing.JPasswordField; 35 import javax.swing.JScrollPane; 36 import javax.swing.JTextArea; 37 import javax.swing.JTextField; 38 import javax.swing.SwingConstants; 39 import javax.swing.border.TitledBorder; 40 41 public class Client extends JFrame { 42 String name; // 网名 43 String ip; // ip地址 44 int port; // 端口 45 Socket c;// 客户端套接字 46 47 JFrame jf1; // 客户端连接窗口 48 JTextField jtf1; // 网名 49 JTextField jtf2; // 输入IP的文本框 50 JTextField jtf3; // 输入端口的文本框 51 52 JFrame jf2;// 登陆界面窗口 53 JTextField jtf4; // 输入账号的文本框 54 JPasswordField jpf; // 输入密码的文本框 55 JLabel jl;// 登录窗口的提示信息 56 String user; 57 String pwd; 58 String pwd1; 59 60 JFrame jf;// 聊天窗口 61 JTextField jtf; // 聊天窗口发送文字的文本框 62 JTextArea jta;// 聊天窗口的信息显示文本域 63 64 JFrame jf3;// 注册窗口 65 JTextField jtf6; // 注册账号的文本框 66 JPasswordField jtf7;// 输入注册密码的文本框 67 JPasswordField jtf8;// 确认密码 68 JLabel jl1; // 账号提示信息 69 JLabel jl2; // 密码提示信息 70 JLabel jl3;// 密码提示信息 71 72 static Map<String, String> map = new HashMap<String, String>();// 存放账号和密码 73 // private JLabel label_1; //密码提示jlable 74 75 // 连接服务器的窗口 76 public Client() { // 默认设置 77 jf1 = this; // 把当前对象设置为jf1; 78 this.setTitle("客户端连接窗口"); 79 setSize(409, 139); 80 Dimension d = Toolkit.getDefaultToolkit().getScreenSize();// 获取当前屏幕size 81 this.setLocation(d.width / 2 - getWidth() / 2, d.height / 2 - getHeight() / 2); // 设置窗口位置居中 82 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 83 setAlwaysOnTop(true); 84 getContentPane().setLayout(null);// 布局方式为绝对布局 85 mouse m = new mouse(); // 新建一个鼠标事件类的实例 86 jtf1 = new JTextField(); // 用户名文本框 87 jtf1.setColumns(10); 88 jtf1.setBounds(89, 10, 185, 30); 89 jtf1.setText("admin"); // 默认用户 90 jtf1.addMouseListener(m); // 给该文本框添加鼠标事件 91 jf1.getContentPane().add(jtf1); 92 jtf2 = new JTextField(); // ip文本框 93 jtf2.setColumns(10); 94 jtf2.setBounds(48, 50, 100, 30); 95 jtf2.setText("127.0.0.1"); // 默认IP 96 jtf2.addMouseListener(m); // 点击清除文本内容事件 97 jf1.getContentPane().add(jtf2); 98 jtf3 = new JTextField(); // port文本框 99 jtf3.setColumns(10); 100 jtf3.setBounds(204, 50, 70, 30); 101 jtf3.setText("8888"); // 默认端口 102 jtf3.addMouseListener(m); 103 jf1.getContentPane().add(jtf3); 104 105 JButton jb = new JButton("连接");// 连接按钮 106 jb.setFont(new Font("宋体", Font.BOLD, 18)); 107 jb.setBounds(294, 28, 89, 52); 108 jf1.getContentPane().add(jb); 109 110 JLabel label = new JLabel("用户名:"); 111 label.setFont(new Font("仿宋", Font.BOLD, 12)); 112 label.setBounds(25, 17, 54, 15); 113 jf1.getContentPane().add(label); 114 JLabel lblIp = new JLabel("IP:"); 115 lblIp.setFont(new Font("仿宋", Font.BOLD, 12)); 116 lblIp.setBounds(25, 57, 54, 15); 117 jf1.getContentPane().add(lblIp); 118 119 JLabel lblPort = new JLabel("PORT:"); 120 lblPort.setFont(new Font("仿宋", Font.BOLD, 12)); 121 lblPort.setBounds(160, 57, 54, 15); 122 jf1.getContentPane().add(lblPort); 123 jb.addActionListener(new ActionListener() { // 点击“连接”触发事件 124 public void actionPerformed(ActionEvent e) { 125 name = jtf1.getText(); 126 String s = jtf2.getText(); 127 String s1 = jtf3.getText(); 128 if (s.matches( 129 "\\b((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\." 130 + "((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\b") 131 && s1.matches("[0-9]{4,6}")) { 132 ip = s; 133 port = new Integer(s1); 134 jf1.setVisible(false); // 原窗口隐藏 135 client(); // 调用客户端启动方法 136 } else { 137 JOptionPane.showMessageDialog(jf1, "请输入正确的地址或IP!"); 138 jtf2.setText(""); 139 jtf3.setText(""); 140 } 141 } 142 }); 143 } 144 145 // 连接服务器的方法 146 public void client() { 147 try { 148 c = new Socket(ip, port); 149 System.out.println("客户端请求连接..."); 150 new Recevie(c).start(); // 启接收信息的线程 151 // map.put("admin", "123456"); 152 login(); // 登录窗口 153 } catch (IOException e) { 154 JOptionPane.showMessageDialog(jf1, "请检查服务器是否开启,ip地址和端口是否正确..."); 155 } 156 } 157 158 // 登录窗口 159 public void login() { 160 // 导入用户信息 161 load(); 162 // 声明 163 Dimension d; 164 JLabel jl1, jl2; 165 JButton jb1, jb2; 166 // 创建设置窗口 167 jf2 = new JFrame(); 168 jtf4 = new JTextField(); // 账号输入框 169 jl1 = new JLabel("账号"); 170 // 设置控件 171 jf2.setTitle("登陆"); 172 jf2.setSize(333, 242); 173 jf2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 174 d = Toolkit.getDefaultToolkit().getScreenSize(); 175 jf2.setLocation(d.width / 2 - jf2.getWidth() / 2, d.height / 2 - jf2.getHeight() / 2); 176 jf2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 177 jf2.getContentPane().setLayout(null); 178 jtf4.setBounds(86, 22, 198, 31); 179 jtf4.setColumns(10); 180 181 jl1.setFont(new Font("宋体", Font.BOLD, 16)); 182 jl1.setBounds(30, 22, 54, 31); 183 jpf = new JPasswordField(); // 登录界面 输入密码 184 jpf.setBounds(87, 82, 197, 31); 185 jpf.setColumns(10); 186 jl2 = new JLabel("密码"); 187 jl2.setFont(new Font("宋体", Font.BOLD, 16)); 188 jl2.setBounds(30, 90, 54, 15); 189 jb1 = new JButton("注册"); 190 jb1.setBounds(34, 171, 93, 23); 191 jb2 = new JButton("登录"); 192 jb2.setBounds(164, 171, 93, 23); 193 jl = new JLabel(""); // 账号密码登录信息提示 194 jl.setBounds(48, 138, 236, 23); 195 196 // 添加控件 197 jf2.getContentPane().add(jpf); 198 jf2.getContentPane().add(jl1); 199 jf2.getContentPane().add(jtf4); 200 jf2.getContentPane().add(jl2); 201 jf2.getContentPane().add(jb1); 202 jf2.getContentPane().add(jb2); 203 jf2.getContentPane().add(jl); 204 205 // 添加事件 206 jtf4.addMouseListener(new MouseAdapter() { 207 public void mouseClicked(MouseEvent e) { 208 jl.setText(""); // 账号提示信息 209 } 210 }); 211 212 jpf.addKeyListener(new KeyAdapter() { 213 public void keyPressed(KeyEvent e) { 214 if ('\n' == e.getKeyChar()) { // 按键事件 按回车键发送信息 215 Set<String> set = map.keySet(); 216 for (String string : set) { 217 String u = string; 218 String p = map.get(string); 219 if (jtf4.getText().equals(u) && jpf.getText().equals(p)) { 220 jf2.setVisible(false); 221 LT(); 222 } 223 } 224 jl.setText("账号或者密码错误!!"); 225 jtf4.setText(""); 226 jpf.setText(""); 227 } 228 } 229 }); 230 jb1.addActionListener(new ActionListener() { 231 public void actionPerformed(ActionEvent arg0) { 232 jf2.setVisible(false); 233 zhuce(); 234 } 235 }); 236 jb2.addActionListener(new ActionListener() { 237 public void actionPerformed(ActionEvent e) { 238 Set<String> set = map.keySet(); 239 for (String string : set) { 240 String u = string; 241 String p = map.get(string); 242 if (jtf4.getText().equals(u) && jpf.getText().equals(p)) { 243 jf2.setVisible(false); 244 LT(); 245 } 246 } 247 jl.setText("账号或者密码错误!!"); 248 jtf4.setText(""); 249 jpf.setText(""); 250 } 251 }); 252 253 jf2.setVisible(true); 254 255 } 256 257 // 注册窗口 258 public void zhuce() { 259 260 // 局部变量 261 JLabel jl11, jl22, jl33; 262 JButton jb1; 263 264 // 创建窗口、事件实例 265 jf3 = new JFrame(); 266 key1 k1 = new key1(); 267 mouse m = new mouse(); 268 269 // 窗口默认设置 270 jf3.getContentPane().setFont(new Font("宋体", Font.PLAIN, 13)); 271 jf3.setTitle("\u6CE8\u518C"); 272 jf3.setSize(411, 287); 273 Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); 274 jf3.setLocation(d.width / 2 - jf3.getWidth() / 2, d.height / 2 - jf3.getHeight() / 2); 275 jf3.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 276 jf3.getContentPane().setLayout(null); 277 278 // 基本控件的设置 279 jtf6 = new JTextField(); // 输入账号的文本框 280 jtf6.setBounds(109, 26, 226, 23); 281 jtf6.setColumns(10); 282 jtf7 = new JPasswordField(); // 第一次输入密码的文本框 283 jtf7.setColumns(10); 284 jtf7.setBounds(109, 84, 226, 23); 285 jtf8 = new JPasswordField(); // 第二次输入密码的文本框 286 jtf8.setColumns(10); 287 jtf8.setBounds(109, 145, 226, 23); 288 jl1 = new JLabel(""); 289 jl1.setBounds(40, 59, 308, 15); 290 jl2 = new JLabel(""); 291 jl2.setBounds(27, 120, 308, 15); 292 jl3 = new JLabel(""); 293 jl3.setBounds(27, 178, 308, 15); 294 jb1 = new JButton("提交"); // 注册信息确认按钮 295 jb1.setBounds(109, 203, 93, 23); 296 jl11 = new JLabel("请输入账号"); 297 jl11.setFont(new Font("宋体", Font.BOLD, 12)); 298 jl11.setBounds(30, 26, 69, 23); 299 jl22 = new JLabel("请输入密码"); 300 jl22.setFont(new Font("宋体", Font.BOLD, 12)); 301 jl22.setBounds(30, 84, 69, 23); 302 jl33 = new JLabel("请再次密码"); 303 jl33.setFont(new Font("宋体", Font.BOLD, 12)); 304 jl33.setBounds(30, 145, 69, 23); 305 306 // 面板添加控件 307 jf3.getContentPane().add(jl11); 308 jf3.getContentPane().add(jl22); 309 jf3.getContentPane().add(jl33); 310 jf3.getContentPane().add(jb1); 311 jf3.getContentPane().add(jl1); 312 jf3.getContentPane().add(jl2); 313 jf3.getContentPane().add(jl3); 314 jf3.getContentPane().add(jtf6); 315 jf3.getContentPane().add(jtf7); 316 jf3.getContentPane().add(jtf8); 317 318 // 添加事件 319 jtf6.addKeyListener(k1); 320 jtf7.addKeyListener(k1); 321 jtf8.addKeyListener(k1); 322 jtf6.addMouseListener(m); 323 jtf7.addMouseListener(m); 324 jtf8.addMouseListener(m); 325 jb1.addActionListener(new ActionListener() { 326 public void actionPerformed(ActionEvent e) { 327 user = jtf6.getText(); 328 pwd = jtf7.getText(); 329 pwd1 = jtf8.getText(); 330 if (user.matches("^(?=.*?[a-zA-Z])(?=.*?[0-9])[a-zA-Z0-9]{6,}$")) { 331 if (pwd.equals(pwd1)) { 332 if (pwd.matches("^(?=.*?[a-zA-Z])(?=.*?[0-9])[a-zA-Z0-9]{6,}$")) { 333 map.put(user, pwd); 334 save(map); 335 JOptionPane.showMessageDialog(jf3, "注册成功!"); 336 jf3.setVisible(false); 337 jf2.setVisible(true); 338 } else { 339 jl2.setText("(密码长度大于等于6且必须包含字符和数字)"); 340 } 341 } else { 342 jl3.setText("(两次输入的密码必须一致)"); 343 } 344 } else { 345 jl1.setText("(用户名长度大于等于6且必须包含字符和数字)"); 346 } 347 } 348 }); 349 jf3.setVisible(true); 350 } 351 352 // 聊天窗口 353 public void LT() { 354 355 // 声明局部变量 356 Dimension d; 357 JScrollPane jsp; 358 JButton jb1, jb2, jb3; 359 360 // 创建实例 361 key k = new key(); 362 jf = new JFrame(); 363 JPanel jp2 = new JPanel(); 364 365 // 设置窗口 366 jf.setBackground(new Color(255, 255, 240)); 367 jf.setTitle("基于TCP协议的聊天窗口---当前用户:" + name); 368 jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 369 jf.setSize(400, 300); 370 jf.setAlwaysOnTop(true); 371 d = Toolkit.getDefaultToolkit().getScreenSize(); 372 jf.setLocation(d.width / 2 - jf.getWidth() / 2, d.height / 2 - jf.getHeight() / 2); 373 374 // 设置控件 375 jp2.setLayout(new BorderLayout(0, 0)); 376 jta = new JTextArea(); // 聊天窗口 377 jta.setBackground(new Color(255, 255, 240)); 378 jta.setFocusable(false);// 禁止鼠标光标进入 379 jsp = new JScrollPane(jta); // 设置滚屏 380 jsp.setBorder(new TitledBorder("聊天内容")); // 设置边框标题 381 jb1 = new JButton("抖动"); // 抖动按钮 382 jb1.setFont(new Font("微软雅黑", Font.BOLD, 12)); 383 jtf = new JTextField(); // 发送文本框 384 jtf.setBackground(new Color(255, 255, 240)); 385 jtf.setColumns(15); 386 jb3 = new JButton("清空"); 387 jb3.setFont(new Font("宋体", Font.BOLD, 12)); 388 jb3.setHorizontalAlignment(SwingConstants.RIGHT); 389 jb2 = new JButton("发送"); 390 jb2.setFont(new Font("微软雅黑", Font.BOLD, 13)); 391 392 // 添加控件 393 jp2.add(jb1, BorderLayout.WEST); 394 jp2.add(jtf, BorderLayout.NORTH); 395 jp2.add(jb3, BorderLayout.EAST); 396 jf.getContentPane().add(jsp); 397 jf.getContentPane().add(jp2, BorderLayout.SOUTH); 398 jp2.add(jb2, BorderLayout.CENTER); 399 400 // 添加事件 401 jtf.addKeyListener(k); 402 jb1.addActionListener(new ActionListener() { 403 public void actionPerformed(ActionEvent e) { 404 BufferedWriter bw; 405 try { 406 bw = new BufferedWriter(new OutputStreamWriter(c.getOutputStream())); 407 bw.write("dyd\n"); 408 bw.flush(); 409 } catch (IOException e2) { 410 e2.printStackTrace(); 411 } 412 } 413 }); 414 jb2.addActionListener(new ActionListener() { 415 public void actionPerformed(ActionEvent arg0) { 416 Send(); 417 } 418 }); 419 jb3.addActionListener(new ActionListener() { 420 public void actionPerformed(ActionEvent e) { 421 jta.setText(""); 422 } 423 }); 424 // 设置窗口可视化 425 jf.setVisible(true); 426 } 427 428 // 成员内部类-自定义鼠标事件-清空文本框内容 429 public class mouse extends MouseAdapter { 430 public void mouseClicked(MouseEvent e) { 431 JTextField j = (JTextField) e.getSource(); 432 j.selectAll(); // 鼠标点击事件 点击清空文本框内容 433 } 434 } 435 436 // 成员内部类-自定义按键事件-回车发送信息 437 public class key extends KeyAdapter { 438 public void keyPressed(KeyEvent e) { 439 if ('\n' == e.getKeyChar()) { // 按键事件 按回车键发送信息 440 Send(); 441 } 442 } 443 } 444 445 // 成员内部类-自定义按键事件-回车确认注册信息 446 public class key1 extends KeyAdapter { 447 public void keyPressed(KeyEvent e) { 448 if ('\n' == e.getKeyChar()) { // 按键事件 按回车键发送信息 449 user = jtf6.getText(); 450 pwd = jtf7.getText(); 451 pwd1 = jtf8.getText(); 452 if (user.matches("^(?=.*?[a-zA-Z])(?=.*?[0-9])[a-zA-Z0-9]{6,}$")) { 453 if (pwd.equals(pwd1)) { 454 if (pwd.matches("^(?=.*?[a-zA-Z])(?=.*?[0-9])[a-zA-Z0-9]{6,}$")) { 455 map.put(user, pwd); 456 save(map); 457 JOptionPane.showMessageDialog(jf3, "注册成功!"); 458 jf3.setVisible(false); 459 jf2.setVisible(true); 460 } else { 461 jl2.setText("(密码长度大于等于6且必须包含字符和数字)"); 462 } 463 } else { 464 jl3.setText("(两次输入的密码必须一致)"); 465 } 466 } else { 467 jl1.setText("(用户名长度大于等于6且必须包含字符和数字)"); 468 } 469 } 470 } 471 472 } 473 474 // 成员内部类-接收聊天信息的线程 475 public class Recevie extends Thread { 476 Socket c; 477 478 public Recevie(Socket c) { 479 this.c = c; 480 } 481 482 public void run() { 483 try { 484 BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); 485 while (true) { 486 String s = br.readLine(); 487 if (s.equals("dyd")) { 488 for (int i = 0; i < 100; i++) { 489 if (i % 2 != 0) 490 jf.setLocation(jf.getX() - 5, jf.getY() + 5); 491 else 492 jf.setLocation(jf.getX() + 5, jf.getY() - 5); 493 } 494 sleep(400); 495 continue; 496 } 497 jta.append(s + "\n"); 498 jta.setCaretPosition(jta.getDocument().getLength()); // 设置光标自动跟踪文本内容 499 } 500 } catch (IOException e) { 501 JOptionPane.showMessageDialog(jf, "服务器已关闭"); 502 } catch (InterruptedException e) { 503 e.printStackTrace(); 504 } 505 } 506 } 507 508 // 发送聊天信息的方法 509 public void Send() { 510 try { 511 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(c.getOutputStream())); 512 String time = new SimpleDateFormat("H:m:s").format(new Date().getTime()); 513 String time1 = new SimpleDateFormat("yyyy-MM-dd").format(new Date().getTime()); 514 bw.write(time1 + "\n" + time + " " + name + ":" + jtf.getText() + "\n"); 515 bw.flush(); 516 jtf.setText(""); 517 } catch (IOException e) { 518 e.printStackTrace(); 519 } 520 } 521 522 // 保存用户信息的方法 523 public void save(Map map) { 524 try { 525 // System.out.println("测试保存"); 526 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("save/user.txt")); 527 oos.writeObject(map); 528 oos.close(); 529 } catch (IOException e) { 530 e.printStackTrace(); 531 } 532 } 533 534 // 读取信息的方法 535 public void load() { 536 try { 537 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("save/user.txt")); 538 Object o = ois.readObject(); 539 map = (Map<String, String>) o; 540 ois.close(); 541 } catch (IOException e) { 542 System.out.println(""); 543 } catch (ClassNotFoundException e) { 544 System.out.println("异常2"); 545 } 546 547 } 548 549 public static void main(String[] args) { 550 new Client().setVisible(true); 551 } 552 }