一、功能介绍
该功能实现了一个类似QQ的最简单多人聊天室,如下图所示。
二、目录结构
三、服务端
1)SocketServer类,该类是服务端的主类,主要负责创建聊天窗口,创建监听客户端的线程:
package multiThreadChatSocketServer; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class SocketServer { private TextArea ta; private TextField tf; private ServerSocket ss; private Socket s; private DataInputStream dis; private DataOutputStream dos; public TextField getTextField() { return tf; } public TextArea getTextArea() { return ta; } public DataInputStream getDataInputStream() { return dis; } public DataOutputStream getDataOutputStream() { return dos; } public static void main(String[] args) { SocketServer socketServer = new SocketServer(); socketServer.createUI(); socketServer.connect(); socketServer.createThread(); } public void close() { try { dis.close(); dos.close(); s.close(); ss.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 创建界面 */ private void createUI(){ Frame f=new Frame("socketServer"); ta = new TextArea(); tf = new TextField(); Button send = new Button("send"); Panel p = new Panel(); p.setLayout(new BorderLayout()); p.add(tf, "Center"); p.add(send, "East"); f.add(ta, "Center"); f.add(p, "South"); MyServerListener listener = new MyServerListener(this); //不管点击发送按钮还是输入框回车,都会触发listener事件 send.addActionListener(listener); tf.addActionListener(listener); //当关闭窗口的时候,退出系统 f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(400,400); f.setVisible(true); } /** * 创建连接 */ public void connect(){ try { ss=new ServerSocket(8888); s=ss.accept(); dis=new DataInputStream(s.getInputStream()); dos=new DataOutputStream(s.getOutputStream()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 启动监听客户端发来的消息的线程 */ public void createThread() { MyServerReader reader = new MyServerReader(this); reader.start(); } }
2)MyServerReader类,该类实时监听客户端输入的信息,如果对方输入“bye”,则退出监听并关闭窗口
package multiThreadChatSocketServer; import java.awt.TextArea; import java.io.DataInputStream; import java.io.IOException; /** * 监听客户端发过来的消息,关显示在服务端的界面上 * @author Administrator * */ class MyServerReader extends Thread { private SocketServer server; public MyServerReader(SocketServer server) { this.server = server; } public void run() { String info; DataInputStream dis = server.getDataInputStream(); TextArea ta = server.getTextArea(); try { while (true) { info = dis.readUTF(); ta.append("对方说: " + info + "\n"); if (info.equals("bye")) { server.close(); System.exit(0); } } } catch (IOException e) { e.printStackTrace(); } } }
3)MyServerListener类,是点发送按钮的时候执行的类
package multiThreadChatSocketServer; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; /** * 当点击发服务端的送按钮的时候,将信息显示在服务端的界面上,并将信息发送给客户端 * @author Administrator * */ class MyServerListener implements ActionListener { private SocketServer server; public MyServerListener(SocketServer server) { this.server = server; } public void actionPerformed(ActionEvent e) { TextField tf = server.getTextField(); String info = tf.getText(); server.getTextArea().append("自己说: " + info + "\n"); try { // writeUTF(value:String) :将 UTF-8 字符串写入字节流。先写入以字节表示的 UTF-8 字符串长度(作为 16 位整数),然后写入表示字符串字符的字节。 // 因为先把字符长度写入二进制,16位能保存的字节长度为65535,超出这个长度会报RangeError。 // writeUTFBytes(value:String):不添加字节长度直接写入字符串的字节数据。因此在读取的时候需要指定字节长度 server.getDataOutputStream().writeUTF(info); } catch (IOException e1) { e1.printStackTrace(); } if (info.equals("bye")) { server.close(); System.exit(0); } tf.setText(""); tf.requestFocus(); } }
四、客户端
1)SocketClient类
package multiThreadChatSocketClient; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class SocketClient { private TextArea ta; private TextField tf; private Socket s; private DataInputStream dis; private DataOutputStream dos; public TextField getTextField() { return tf; } public TextArea getTextArea() { return ta; } public DataInputStream getDataInputStream() { return dis; } public DataOutputStream getDataOutputStream() { return dos; } public static void main(String[] args) { SocketClient socketClient = new SocketClient(); socketClient.createUI(); socketClient.connect(); socketClient.createThread(); } public void close() { try { dis.close(); dos.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 创建界面 */ private void createUI(){ Frame f=new Frame("socketClient"); ta = new TextArea(); tf = new TextField(); Button send = new Button("send"); Panel p = new Panel(); p.setLayout(new BorderLayout()); p.add(tf, "Center"); p.add(send, "East"); f.add(ta, "Center"); f.add(p, "South"); MyClientListener listener = new MyClientListener(this); //不管点击发送按钮还是输入框回车,都会触发listener事件 send.addActionListener(listener); tf.addActionListener(listener); //当关闭窗口的时候,退出系统 f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(400,400); f.setVisible(true); } /** * 创建连接 */ public void connect(){ try { s = new Socket("127.0.0.1", 8888); dis=new DataInputStream(s.getInputStream()); dos=new DataOutputStream(s.getOutputStream()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 启动监听服务端发来的消息的线程 */ public void createThread() { MyClientReader reader = new MyClientReader(this); reader.start(); } }
2)MyClientReader类
package multiThreadChatSocketClient; import java.awt.TextArea; import java.io.DataInputStream; import java.io.IOException; /** * 监听服务端发过来的消息,关显示在客户端的界面上 * @author Administrator * */ class MyClientReader extends Thread { private SocketClient client; public MyClientReader(SocketClient client) { this.client = client; } public void run() { String info; DataInputStream dis = client.getDataInputStream(); TextArea ta = client.getTextArea(); try { while (true) { info = dis.readUTF(); ta.append("对方说: " + info + "\n"); if (info.equals("bye")) { client.close(); System.exit(0); } } } catch (IOException e) { e.printStackTrace(); } } }
3)MyClientListener类
package multiThreadChatSocketClient; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; /** * 当点击客户端的发送按钮的时候,将信息显示在客户端的界面上,并将信息发送给服务端 * @author Administrator * */ class MyClientListener implements ActionListener { private SocketClient client; public MyClientListener(SocketClient client) { this.client = client; } public void actionPerformed(ActionEvent e) { TextField tf = client.getTextField(); String info = tf.getText(); client.getTextArea().append("自己说: " + info + "\n"); try { client.getDataOutputStream().writeUTF(info); } catch (IOException e1) { e1.printStackTrace(); } if (info.equals("bye")) { client.close(); System.exit(0); } tf.setText(""); tf.requestFocus(); } }