基于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 }
客户端:
注:注册和登录没有实现对注册的账号和密码的判断(账号是否已经使用)。
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协议与搭建简易聊天室