模拟线程通信中群聊的小练习(3.18)回头详细说

需求:

        启动多个客户端放送消息,以及一个服务端;来模拟群聊的功能

思路:

        启动多个线程发送到服务端,服务端里在由一个线程发消息给其他线程,然后其他线程接收后再返回消息。先启动服务端,再启动客户端

代码:

Client类
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

//完成TCP通信快速入门-客户端开发,实现多个客户端群聊
// (其实就是第一个客户端连接到服务端后,在服务端依次给其他客户端传进来的线程发消息)
public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建socket对象,并同时请求与服务器程序的连接。
        Socket socket=new Socket("127.0.0.1",8888);

        //创建一个独立的线程,负责随时从socket中接收服务端发送过来的消息
        new ClentReaderThread(socket).start();

        //2.从socket通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();
        //3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        //实现多发多收
        Scanner sc=new Scanner(System.in);
        while (true) {
            System.out.println("请输入:");
            String msg=sc.nextLine();

            //一旦用户输入了exit,就退出客户端程序
            if ("exit".equals(msg)){
                System.out.println("欢迎您下次光临,退出成功");
                dos.close();//记得关闭流
                socket.close();
                break;
            }

            //4.开始写数据出去了
            dos.writeUTF(msg);
            dos.flush();//把数据刷新出去,立即发送给服务端的意思
        }

        /*dos.close();//关闭释放流
        //关闭管道,释放连接资源
        socket.close();*/
    }
}
ClentReaderThread类
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;

//创建的这个线程,给客户端读线程
public class ClentReaderThread extends Thread{
    private Socket socket;
    public ClentReaderThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        try {
            InputStream is=socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true){
                try {
                    String msg = dis.readUTF();//不断去读服务端发送过来的消息
                    System.out.println(msg);
                } catch (Exception e) {
                    System.out.println("自己下线了:"+socket.getRemoteSocketAddress());
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Server类
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

//完成TCP通信快速入门-服务端开发:实现1发1收
public class Server {
    public static List<Socket> onLineSockets=new ArrayList<>();
    public static void main(String[] args) throws Exception {
        System.out.println("---服务端启动成功---");
        //1.创建ServerSocket的对象,同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8888);

        while (true) {
            //2.使用serverSocket对象,调用一个accept方法,等待客户端的连接请求。
            Socket socket = serverSocket.accept();//调这个方法后,程序就会在等待客户端请求
            //添加socket到集合里
            onLineSockets.add(socket);
            System.out.println("有人上线了:"+socket.getRemoteSocketAddress());

            //3.把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
            new ServerReaderThread(socket).start();
        }
    }
}
ServerReaderThread类
import java.io.*;
import java.net.Socket;

public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        try {
            InputStream is=socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true){
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);
                    //把这个消息分发给全部客户端
                    sendMagToAll(msg);
                } catch (Exception e) {
                    System.out.println("有人下线了:"+socket.getRemoteSocketAddress());
                    //服务端将离线的线程抹掉
                    Server.onLineSockets.remove(socket);
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendMagToAll(String msg) throws IOException {
        //发送给全部在线的socket管道接收 Server.onLineSockets.for
        for (Socket onLineSocket : Server.onLineSockets) {
            OutputStream os = onLineSocket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);
            dos.writeUTF(msg);
            dos.flush();//刷新一下确保发出去
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值