基于TCP协议的服务器中转简易聊天

Posted 倦刻懒骨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于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 }
View Code

客户端:

注:注册和登录没有实现对注册的账号和密码的判断(账号是否已经使用)。

  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学习JavaSE TCP/IP协议与搭建简易聊天室

SpringBoot + WebSocket实现简易聊天室

网络编程之java简易聊天室实现

网络协议分析课程设计:基于TCP协议网上聊天程序

Java实现简易聊天室

Unity 简易聊天室(基于TCP)