实现Java简单的聊天室
所用主要知识:多线程+网络编程
效果如下图
/**
*
* @author Administrator
*
* 简单的多人聊天系统——重点:同时性,异步性
* 1、客户端:发送消息,并且接收消息
* 1.1 消息发送至服务器:服务器每次都将客户发过来的信息发送到每个客户端
* 1.2 接收消息:发送的同时也要接收消息,所以必须有两个线程,一个发送消息,一个接收消息
* 1.3 关于这两个线程:如果没有线程,接收和发送就是按顺序执行的了,那么是发送后接收还是接收后发送?或者是
* 一边可以发送一边又可以接收呢?答案不言而喻
* 1.4 在客户端,用可以通过界面的点击按钮事件发送消息,所以就要开启一个线程来接收服务器发送给客户端的消息了
* 1.5 多线程:不需按步骤逐步循环,可以和其他程序同时执行,不相互干扰
* 2、服务器端:接收所有用户的消息并且借每个用户的消息发送给连接了服务器的客户端
* 2.1 服务器既要接收C端信息又要想所有C端发送信息,先收后发。一收就发。
* 2.2 S端还要显示C端上线提醒
* 2.3 上线提醒和收发信息是不影响的,互不干扰的,但是都要在S端上执行,如果没有线程,所以的程序都要按顺序执行了所以又要 多线程
* 2.4 一个线程负责向所以C端发送接收到的任何一条信息,一个线程负责显示C端上线的信息
*
* 3、类:S端:Server、ServerFrame、sendThread 三个类
* C端:Client、ClientFrame 两个类
*
*/
1 package com.java.chat; 2 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 import java.io.BufferedReader; 6 import java.io.BufferedWriter; 7 import java.io.IOException; 8 import java.io.InputStream; 9 import java.io.InputStreamReader; 10 import java.io.OutputStream; 11 import java.io.OutputStreamWriter; 12 import java.net.ServerSocket; 13 import java.net.Socket; 14 import java.util.ArrayList; 15 import java.util.List; 16 17 import javax.swing.JButton; 18 import javax.swing.JFrame; 19 import javax.swing.JTextArea; 20 21 22 public class Server { 23 //用于保存Socket的集合,也可以说是把个C端与S端的一个连接通道保存起来 24 //作用:服务器将接收到的信息发给集合里的所以socket,也就是发给每个C端 25 public static List<Socket> list = new ArrayList<Socket>(); 26 27 public static void main(String[] args) { 28 new ServerFrame("服务器端"); 29 } 30 31 } 32 33 /* 34 * 继承Jframe类表示该类可以创建一个窗口程序了, 35 * 实现ActionListener:动作监听,在S端点击“启动服务器”是要执行的代码 36 * 实现Runnable:实现多线程,该窗口是个客户端窗口,要开启一个线程接收显示服务器发过来的信息 37 */ 38 class ServerFrame extends JFrame implements ActionListener, Runnable { 39 40 private static final long serialVersionUID = 1L; 41 42 private ServerSocket serverSocket = null; 43 44 private Socket socket; 45 46 private JButton start; 47 private JTextArea message; 48 49 public ServerFrame(String name) { 50 super(name); 51 52 start = new JButton("启动服务器"); 53 start.addActionListener(this); 54 message = new JTextArea(); 55 message.setEditable(false); 56 this.add(start, "North"); 57 this.add(message, "Center"); 58 59 this.setResizable(false); 60 this.setBounds(0, 0, 400, 300); 61 this.setVisible(true); 62 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 63 } 64 65 @Override 66 public void actionPerformed(ActionEvent e) { 67 if (e.getSource() == start) { 68 // 如果点击的按钮是开始按钮。则启动服务器。 69 try { 70 serverSocket = new ServerSocket(6666); 71 message.setText("服务器已启动。。。"); 72 73 //单击“启动服务器”开启一个线程用于获取用户上线的情况 74 new Thread(this).start(); 75 76 } catch (IOException e1) { 77 e1.printStackTrace(); 78 } 79 } 80 } 81 82 //获取C端上线的情况 83 @Override 84 public void run() { 85 String address = null; 86 int port = 0; 87 //用一个死循环一直让S端开启接收C端的连接,将C端的IP和端口显示在面板上 88 //如果用循环的话就只能接收一次 89 while (true) { 90 try { 91 socket = serverSocket.accept(); 92 Server.list.add(socket); 93 address = socket.getInetAddress().getHostAddress(); 94 port = socket.getPort(); 95 message.append("\r\nip/" + address + ":" + port + "\t上线了"); 96 97 //开启转发信息的线程 98 new sendThread(socket).start(); 99 100 } catch (IOException e) { 101 // System.out.println(address + ":" + port + "\t退出了服务器"); 102 } 103 } 104 } 105 106 } 107 108 /* 109 * 接收每个C端的信息并向每个C端发送接收到的信息 110 */ 111 class sendThread extends Thread { 112 private Socket socket; 113 114 public sendThread(Socket socket) { 115 super(); 116 this.socket = socket; 117 } 118 119 @Override 120 public void run() { 121 InputStream is = null; 122 BufferedReader br = null; 123 String str = null; 124 OutputStream os = null; 125 BufferedWriter bw = null; 126 while (true) { 127 try { 128 is = socket.getInputStream(); 129 br = new BufferedReader(new InputStreamReader(is)); 130 str = br.readLine(); 131 for (Socket s : Server.list) { 132 os = s.getOutputStream(); 133 bw = new BufferedWriter(new OutputStreamWriter(os)); 134 bw.write(str); 135 bw.newLine(); 136 bw.flush(); 137 } 138 } catch (IOException e) { 139 //如果断开连接则移除对于的socket 140 Server.list.remove(socket); 141 } 142 } 143 } 144 }