基于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 }

时间: 2024-10-06 10:22:41

基于TCP协议的服务器中转简易聊天的相关文章

Android基础入门教程——7.6.3 基于TCP协议的Socket通信(2)

Android基础入门教程--7.6.3 基于TCP协议的Socket通信(2) 标签(空格分隔): Android基础入门教程 本节引言: 上节中我们给大家接触了Socket的一些基本概念以及使用方法,然后写了一个小猪简易聊天室的 Demo,相信大家对Socket有了初步的掌握,本节我们来学习下使用Socket来实现大文件的断点续传! 这里讲解的是别人写好的一个Socket上传大文件的例子,不要求我们自己可以写出来,需要的时候会用 就好! 1.运行效果图: 1.先把我们编写好的Socket服务

Android基础入门教程——7.6.2 基于TCP协议的Socket通信(1)

Android基础入门教程--7.6.2 基于TCP协议的Socket通信(1) 标签(空格分隔): Android基础入门教程 本节引言: 上一节的概念课枯燥无味是吧,不过总有点收获是吧,本节开始我们来研究基于TCP协议的Socket 通信,先来了解下Socket的概念,以及Socket通信的模型,实现Socket的步骤,以及作为Socket服务 端与客户端的两位各做要做什么事情!好的,我们由浅入深来扣这个Socket吧! 1.什么是Socket? 2.Socket通信模型: Socket通信

Java中的基于Tcp协议的网络编程

一:网络通信的三要素? IP地址     端口号     通信协议 IP地址:是网络中设备的通信地址.由于IP地址不易记忆,故可以使用主机名.本地环回地址,127.0.0.1   本地主机名localhost 端口号:发送端准备的数据要发送到指定的目的应用程序上,为了标识这些应用程序,所以用网络数字来标识这些不同的应用程序,这些数 字称为端口号.端口号是不同进程之间的标识.一般来说,有0~65535的端口可供使用,但是1~1024系统使用,或者称作保留端口. 通信协议:指定义的通信规则,这个规则

网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服务器进程B1同时为客户进程A1.A2和B2提供服务. Socket概述 ①   所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过“套接字”向网络发出请求或者应答网络请求. ②   Socket是连接运行在网络上的两个程序间的双向通信的端点. ③  

用c++开发基于tcp协议的文件上传功能

用c++开发基于tcp协议的文件上传功能 2005我正在一家游戏公司做程序员,当时一直在看<Windows网络编程> 这本书,把里面提到的每种IO模型都试了一次,强烈推荐学习网络编程的同学阅读,比 APUE 讲的更深入 这是某个银行广告项目(p2p传输视频)的一部分 IO模型采用的阻塞模式,文件一打开就直接上传 用vc 2003编译,生成win32 dll 麻雀虽小五脏俱全,CSimpleSocket,CReadStream dll 输出一虚类 extern "C" __d

浅析C#基于TCP协议的SCOKET通信

TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实现不是一天两天的功夫,所幸的是在.net framework环境下,我们不必要去追究TCP协议底层的实现,一样可以很方便的编写出基于TCP协议进行网络通讯的程序. C#基于TCP协议的网络通讯 要进行C#基于TCP协议的网络通讯,首先必须建立同远程主机的连接,连接地址通常包括两部分--主机名和端口,

基于TCP协议的简单Socket通信笔记(JAVA)

好久没写博客了,前段时间忙于做项目,耽误了些时间,今天开始继续写起~ 今天来讲下关于Socket通信的简单应用,关于什么是Socket以及一些网络编程的基础,这里就不提了,只记录最简单易懂实用的东西. 1.首先先来看下基于TCP协议Socket服务端和客户端的通信模型: Socket通信步骤:(简单分为4步) 1.建立服务端ServerSocket和客户端Socket 2.打开连接到Socket的输出输入流 3.按照协议进行读写操作 4.关闭相对应的资源 2.相关联的API: 1.首先先来看下S

c# UDP/TCP协议简单实现(简单聊天工具)

长时间没有摸这两个协议,写个代码温习下 下面是界面 [服务器界面] [登陆界面] [好友列表界面(我登陆了2个)] [聊天界面] 下面大致讲解下用到的内容 1.用户登陆于服务器通信用到的tcp协议,服务器接收到用户登陆信息(包括ip,端口,用户名等)后,返回已经登陆的用户列表信息(包括ip,端口,用户名等)给这个用户,同时服务器使用Udp协议向已经登陆的用户发送最新用户列表(包括ip,端口,用户名等)用于更新用户列表 2.用户登陆成功后展示好友列表,并启动udp协议的监听(叫监听似乎不太合适,暂

(1)网络编程的常识 (2)基于tcp协议的编程模型 (3)tcp协议和udp协议的比较 (4)基于udp协议的编程模型

1.网络编程的常识 目前主流的网络通讯软件有:微信.QQ.YY.陌陌.探探.飞信.阿里旺旺.... 在吗? 1.1 七层网络模型(熟悉) 为了保证数据传递的可靠安全等等,ISO(国际标准委员会组织)将数据的传递从逻辑上划分为以下七层: 应用层.表示层.会话层.传输层.网络层.数据链路层.物理层. 在发送数据之前要按照上述七层协议从上到下一层一层进行加包处理,再发送出去; 在接收数据之后要按照上述七层协议从下到上一层一层进行拆包处理,再解析出来: 1.2 常用的协议(熟悉) http协议 - 超文