Socket套接字及多线程实现在线群聊示例
代码:
Server.java
package com.du;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
/**
* 注意先得开启服务
* 服务器的套接字类,实现接受多个客户端套接字
* 当有一个客户端套接字发言了,我们把这个发言的内容传递给所有的在服务器端存储的客户端的套接字对象
*/
public class Server {
private Vector<Socket> vector = new Vector<>();//存储客户端套接字集合对象
private StringBuffer sb = new StringBuffer();////定义一个可变长度的字符串,用来保存所有的聊天内容
//主方法
public static void main(String[] args) {
Server server = new Server();
server.testServer();
}
public void testServer(){
ServerSocket server = null;
Socket client = null;
try {
server = new ServerSocket(6666);;//创建服务器套接字对象,端口:6666
System.out.println("服务器启动了");
while (true){
client = server.accept();//阻塞,等待客户端套接字连接进来
System.out.println(client.getRemoteSocketAddress()+"连接进来了");
vector.add(client);//把连接进来的客户端套接字存储起来
new ServerThread(client,vector,sb).start();//创建并启动线程负责数据输入输出
}
}catch (Exception e){
//关闭资源
if(server!=null){
try {
//Unhandled Exception:java.io.IOException——>Ctrl+Alt+t
server.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}
class ServerThread extends Thread{
private Socket client;//当前的客户端套接字
private Vector<Socket> vector;//存储当前连接服务端的所有客户端套接字对象
private StringBuffer sb;//保存聊天的所有内容
public ServerThread(Socket client,Vector<Socket> vector,StringBuffer sb){
this.client = client;
this.vector = vector;
this.sb = sb;
}
@Override
public void run() {
DataInputStream dis = null;
DataOutputStream dos = null;
try {
dis = new DataInputStream(client.getInputStream());
//给新连进来的客户端套接字发送前面聊天的内容
dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(sb.toString());
dos.flush();
while(true) {
String info = dis.readUTF();//读取客户端套接字传输过来的内容
info = client.getRemoteSocketAddress() + ":" + info;
//保存到数据中
//id dt content
System.out.println("我是服务器,读取到客户端发送过来的信息:" + info);
sb.append(info+"\n\r");//把聊天的记录保存起来
//把info的内容传输到当前连接服务端的所有客户端套接字对象
for(int i = 0;i<vector.size();i++) {
Socket client = vector.get(i);//得到集合中客户端套接字对象
dos = new DataOutputStream(client.getOutputStream());//数据输出流对象
dos.writeUTF(info);//写info到所有客户端套接字去
dos.flush();
}
}
}catch(Exception e) {
vector.remove(client);//下线后,从vector集合中移除
System.out.println(client.getRemoteSocketAddress() + "下线了");
}finally {//关闭资源
if(dis != null)
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
if(dos != null)
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
if(client != null)
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Client.java
package com.du; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; /** * 图形界面客户端 */ public class Client extends JFrame { private JTextField textField; private JTextArea textArea; private JButton button; private DataOutputStream dos = null;// 数据的输出流,用来写入数据 public Client() { setTitle("在线群聊"); getContentPane().setLayout(null); JScrollPane scrollPane = new JScrollPane(); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scrollPane.setBounds(12, 10, 506, 242); setBounds(10, 10, 544, 418);//设置窗口的出现坐标及它的宽与长 setLocationRelativeTo(null);//居中显示 getContentPane().add(scrollPane); textArea = new JTextArea(); scrollPane.setViewportView(textArea); textArea.setEditable(false); textArea.setRows(10); textField = new JTextField(); textField.setBounds(23, 308, 240, 21); getContentPane().add(textField); textField.setColumns(10); button = new JButton("发言"); button.addActionListener(new ActionListener() {//点击按钮,发言聊天的内容 public void actionPerformed(ActionEvent e) { String info = textField.getText(); try { dos.writeUTF(info);//传到服务器上去内容 dos.flush(); textField.setText("");//清空文本框 } catch (IOException e1) { e1.printStackTrace(); } } }); button.setBounds(330, 308, 93, 23); getContentPane().add(button); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { Client client = new Client(); client.clientTest(); } public void clientTest() { Socket client = null; DataInputStream dis = null;// 数据的输入流,用来读取数据 try { // 得到套接字对象第一个参数是服务端的地址,第二个参数是端口号 client = new Socket("127.0.0.1", 6666); // 得到数据的输出流 dos = new DataOutputStream(client.getOutputStream()); // 得到数据的输入流 dis = new DataInputStream(client.getInputStream()); new ClientThread(dis).start();//专门读取从服务器端传递过来的信息 } catch (Exception e) { e.printStackTrace(); } } //客户端读取服务器端发送过来的内容以线程的形式 class ClientThread extends Thread{ private DataInputStream dis; public ClientThread(DataInputStream dis) { this.dis = dis; } @Override public void run() { try { while(true) { String info = dis.readUTF();//读取服务端传递过来信息 textArea.append(info+"\n\r");//在多文本框中显示内容,并加回车换行符 } }catch(Exception e) { e.printStackTrace(); }finally { if(dis != null) try { dis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }