实现思路
- 服务器端循环获取所有的客户端socket,放到一个
socket的list
中,等到需要通信的时候,调用相对应的管道就可以了- 客户端和服务器端一样,纪要发送消息,也要接受消息
代码
客户端
// tcp客户端
public class Client {
public static void main(String[] args) throws IOException {
// 1. 创建一个Socket对象
// 参数一:服务端的ip地址
// 参数二:服务端的端口号
Socket socket = new Socket("127.0.0.1", 8888);
// 创建一个独立的线程负责读取服务端发送过来的数据
ClientReaderThread clientReaderThread = new ClientReaderThread(socket);
clientReaderThread.start();
// 2. 通过Socket对象获取一个输出流
OutputStream outputStream = socket.getOutputStream();
// 3. 把低级的字节输出流包装成高级的数据输出流
// 这一步不是必须得,但是高级的数据输出流可以更方便的操作数据
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入要发送的数据:");
String s = scanner.nextLine();
// 4. 使用数据输出流向服务端发送数据
dataOutputStream.writeUTF(s);
dataOutputStream.flush();
if (s.equals("exit")) {
System.out.println("客户端退出");
// 5. 关闭资源
// dataOutputStream关闭的时候会自动关闭outputStream
dataOutputStream.close();
socket.close();
Server.removeSocket(socket);
break;
}
}
}
}
客户端读取线程
读取线程是子线程文章来源地址https://www.toymoban.com/news/detail-860537.html
public class ClientReaderThread extends Thread {
private Socket socket;
public ClientReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (
// 1. 通过Socket对象获取一个输入流
InputStream inputStream = socket.getInputStream();
// 2. 将原始的字节输入流包装成高级的数据输入流
// 这一步不是必须的,但是高级的数据输入流可以更方便的操作数据
DataInputStream dataInputStream = new DataInputStream(inputStream);
) {
while (true) {
// 3. 读取客户端发送过来的数据
String data = dataInputStream.readUTF();
System.out.println("客户端发送过来的数据:" + data);
System.out.println("客户端的ip地址:" + socket.getInetAddress().getHostAddress()
+ ",客户端的端口号:" + socket.getPort());
if (data.equals("exit")) {
System.out.println("客户端退出");
// 4. 关闭资源
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务端
// tcp服务端
public class Server {
// 用来存储所有的socket对象
private static ArrayList<Socket> onLineSockets = new ArrayList<Socket>();
public static void main(String[] args) throws IOException {
// 1. 创建服务端对象
// 参数:服务端的端口号
ServerSocket server = new ServerSocket(8888);
while(true){
// 2. 服务端一直处于监听状态,等待客户端的连接
// accept()方法是一个阻塞方法,会一直等待客户端的连接
Socket socket = server.accept();
// 将socket对象存储到集合中
onLineSockets.add(socket);
// 3. 将socket独享交给独立的线程去负责
ServerReaderThread serverReaderThread = new ServerReaderThread(socket);
serverReaderThread.start();
}
}
public static void removeSocket(Socket socket){
onLineSockets.remove(socket);
}
public static ArrayList<Socket> getOnLineSockets(){
return onLineSockets;
}
}
服务段读取线程
public class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (
// 1. 通过Socket对象获取一个输入流
InputStream inputStream = socket.getInputStream();
// 2. 将原始的字节输入流包装成高级的数据输入流
// 这一步不是必须的,但是高级的数据输入流可以更方便的操作数据
DataInputStream dataInputStream = new DataInputStream(inputStream);
) {
while (true) {
// 3. 读取客户端发送过来的数据
String data = dataInputStream.readUTF();
// System.out.println("客户端发送过来的数据:" + data);
// System.out.println("客户端的ip地址:" + socket.getInetAddress().getHostAddress()
// + ",客户端的端口号:" + socket.getPort());
// 4. 将客户端发送过来的数据转发给所有的客户端
sendMsgToAllClient(data);
if (data.equals("exit")) {
System.out.println("客户端退出");
// 4. 关闭资源
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 异常抛出给上一级
private void sendMsgToAllClient(String data) throws Exception{
// 1. 获取所有的socket对象
for (Socket socket : Server.getOnLineSockets()) {
// 2. 通过socket对象获取一个输出流
// 3. 将原始的字节输出流包装成高级的数据输出流
// 这一步不是必须的,但是高级的数据输出流可以更方便的操作数据
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
// 4. 使用数据输出流向客户端发送数据
dataOutputStream.writeUTF(data);
dataOutputStream.flush();
}
}
}
缺点
- 只能实现群发,无法端到端
- 也会发给自己
文章来源:https://www.toymoban.com/news/detail-860537.html
到了这里,关于TCP案例-实时群聊的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!