多个客户端--多人聊天室

2019-07-09 22:38 更新

1.服务端: 接收一个用户的消息,将其转发给其他连接的用户。

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;


/**
 * 创建服务器
 * 发送数据:输出流
 * 接收数据:输入流
 */
public class MyServer {
    private List<MyChannel> all = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        new MyServer().start();
    }
    public void start() throws IOException {
        ServerSocket server = new ServerSocket(8888);
        while(true) {
            //main线程:用于不断连接用户,将连接放到list中保存,启动专门用于转发消息的线程。
            Socket socket = server.accept();
            MyChannel myChannel = new MyChannel(socket);
            all.add(myChannel);
            new Thread(myChannel).start();
        }
    }

    
    /**
     * 一个客户端一条道路,
     * 一个客户端一个线程。
     * 1.输入流
     * 2.输出流
     * 3.接收数据
     * 4.发送数据
     * 成员内部类,静态方法不能访问。
     * 服务端转发数据线程。
     */
    class MyChannel implements Runnable{
        //输入流
        private DataInputStream dis;
        //输出流
        private DataOutputStream dos;
        //控制线程的标识符
        private boolean isRunning = true;
        //初始化建立管道
        public MyChannel(Socket socket) {
            try {
                dis = new DataInputStream(socket.getInputStream());
                dos = new DataOutputStream(socket.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
                CloseUtil.closeAll(dis, dos);
                all.remove(this);
                isRunning = false;
            }
        }
        //读取数据
        private String receive() {
            String msg = "";
            try {
                msg = dis.readUTF();
            } catch (IOException e) {
                e.printStackTrace();
                CloseUtil.closeAll(dis, dos);
                all.remove(this);
                isRunning = false;
            }
            return msg;
        }
        //发送给this数据
        private void send(String msg) {
            if(msg == null || msg.equals("")) {
                return;
            }
            try {
                dos.writeUTF(msg);
                dos.flush();
            } catch (IOException e) {
                e.printStackTrace();
                CloseUtil.closeAll(dis, dos);
                all.remove(this);
                isRunning = false;
            }
        }
        //发送给其他客户端
        private void sendOthers() {
            String msg = receive();
            //遍历容器
            for(MyChannel other : all) {
                if(other == this) {
                    continue;
                }
                //发送给其他客户端
                other.send(msg);
            }
        }
        @Override
        public void run() {
            while(isRunning){
                sendOthers();
            }
        }
    }
}

2.客户端:

import java.io.IOException;
import java.net.Socket;
/**
 * 创建客户端:发送数据+接收数据
 * 发送数据:输出流
 * 接收数据:输入流
 * 输出流和输入流应该彼此独立,使用线程处理。
 */
public class MyClient {
    public static void main(String[] args) throws IOException {
        Socket client = new Socket("localhost", 8888);
        //发送  控制台输入并发送到服务端
        new Thread(new Send(client)).start();//一条路径
        //接收  接收服务端数据并打印
        new Thread(new Receive(client)).start();//一条路径
    }
}

客户端发送数据--线程 从控制台接收数据,发送到服务端。

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;


/**
 * 发送数据  线程
 */
public class Send implements Runnable{
    //控制台输入流
    private BufferedReader console;
    //管道输出流
    private DataOutputStream dos;
    //控制线程的标识符
    private boolean isRunning = true;
    //初始化建立管道
    public Send(Socket socket) {
        try {
            console = new BufferedReader(new InputStreamReader(System.in));
            dos = new DataOutputStream(socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
            CloseUtil.closeAll(dos, console);
        }
    }

    
    /**
     * 1.从控制台接收数据
     * 2.向服务端发送数据
     */
    //1.从控制台接收数据
    private String getMsgFromConsole() {
        String msg = "";
        try {
            msg = console.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
            CloseUtil.closeAll(dos, console);
        }
        return msg;
    }
    //2.向服务端发送数据
    private void send() {
        String msg = getMsgFromConsole();
        try {
            if(msg != null && !msg.equals("")) {
                dos.writeUTF(msg);
                dos.flush();//强制刷新
            }
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
            CloseUtil.closeAll(dos, console);
        }
    }
    @Override
    public void run() {
        //线程体
        while(isRunning) {
            send();
        }
    }
}

客户端接收数据--线程 从服务端接收数据并打印

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;


public class Receive implements Runnable{
    //输入流
    private DataInputStream dis;
    //线程标识符
    private boolean isRunning = true;
    //初始化建立管道
    public Receive(Socket socket) {
        try {
            dis = new DataInputStream(socket.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
            CloseUtil.closeAll(dis);
        }
    }
    /**
     * 接收数据
     */
    private String receive() {
        String msg = "";
        try {
            msg = dis.readUTF();
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
            CloseUtil.closeAll(dis);
        }
        return msg;
    }

    
    @Override
    public void run() {
        //线程体
        while(isRunning) {
            System.out.println(receive());
        }
    }
}

3.关闭流工具类:

import java.io.Closeable;
import java.io.IOException;


/**
 * 关闭io流的工具
 */
public class CloseUtil {
    public static void closeAll(Closeable... io) {
        for(Closeable temp : io) {
            try {
                if(temp != null) {
                    temp.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号