多個客戶端--多人聊天+私聊

2019-07-09 22:34 更新

在多人聊天室的基礎(chǔ)上增加了私聊功能。 實現(xiàn)方法:在Send類中添加name區(qū)別客戶端,用于客戶端;在MyChannel中添加name區(qū)別客戶端連接,用于服務(wù)端。 1.服務(wù)端

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;


/**
 * 創(chuàng)建服務(wù)器
 * 發(fā)送數(shù)據(jù):輸出流
 * 接收數(shù)據(jù):輸入流
 */
public class MyServer {
    //存放服務(wù)端與客戶端的連接
    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) {
            Socket socket = server.accept();
            MyChannel myChannel = new MyChannel(socket);
            all.add(myChannel);
            new Thread(myChannel).start();
        }
    }
    /**
     * 一個客戶端一條道路,
     * 一個客戶端一個線程。
     * 1.輸入流
     * 2.輸出流
     * 3.接收數(shù)據(jù)
     * 4.發(fā)送數(shù)據(jù)
     * 成員內(nèi)部類,靜態(tài)方法不能訪問。
     */
    class MyChannel implements Runnable{
        //輸入流
        private DataInputStream dis;
        //輸出流
        private DataOutputStream dos;
        //控制線程的標(biāo)識符
        private boolean isRunning = true;
        //名稱  給每個連接命名,區(qū)別客戶端  不考慮重名
        private String name;
        //初始化建立管道
        public MyChannel(Socket socket) {
            try {
                dis = new DataInputStream(socket.getInputStream());
                dos = new DataOutputStream(socket.getOutputStream());

                
                name = dis.readUTF();

                
                send("歡迎您進入聊天室!");//發(fā)送給自己客戶端
                sendOthers(name + "進入了聊天室!", true); //發(fā)給其他的客戶端
            } catch (IOException e) {
                e.printStackTrace();
                CloseUtil.closeAll(dis, dos);
                all.remove(this);
                isRunning = false;
            }
        }
        //讀取數(shù)據(jù)
        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;
        }
        //發(fā)送給this數(shù)據(jù)
        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;
            }
        }
        //發(fā)送給其他客戶端
        private void sendOthers(String msg, boolean isSysMsg) {
            //是否為私聊
            if(msg.startsWith("@") && msg.indexOf(":") != -1) {//向一個特定的人發(fā)消息,格式為@xxx:message
                //獲取name
                String name = msg.substring(1, msg.indexOf(":"));
                //獲取內(nèi)容
                String content = msg.substring(msg.indexOf(":") + 1);
                for(MyChannel other:all) {
                    if(other.name.equals(name)) {
                        other.send(this.name + "對您悄悄地說:" + content);
                    }
                }
            } else {//向全體發(fā)消息
                //遍歷容器
                for(MyChannel other : all) {
                    if(other == this) {
                        continue;
                    }
                    if(isSysMsg) {//是系統(tǒng)消息
                        //發(fā)送給其他客戶端
                        other.send("系統(tǒng)信息:" + msg);
                    } else {//不是系統(tǒng)消息
                        //發(fā)送給其他客戶端
                        other.send(name + "對所有人說:" + msg);
                    }

                    
                }
            }
        }
        @Override
        public void run() {
            while(isRunning) {
                sendOthers(receive(), false);
            }
        }
    }
}

2.客戶端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
 * 創(chuàng)建客戶端:發(fā)送數(shù)據(jù)+接收數(shù)據(jù)
 * 發(fā)送數(shù)據(jù):輸出流
 * 接收數(shù)據(jù):輸入流
 * 輸出流和輸入流應(yīng)該彼此獨立,使用線程處理。
 * 加入名稱。
 */
public class MyClient {
    public static void main(String[] args) throws IOException {
        //通過名稱判斷不同的客戶 端,存放在Send類中。
        System.out.println("請輸入名稱:");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String name = br.readLine();
        if(name.equals("")) {
            return;
        }

        
        Socket client = new Socket("localhost", 8888);
        //發(fā)送  控制臺輸入并發(fā)送到服務(wù)端
        new Thread(new Send(client, name)).start();//一條路徑
        //接收  接收服務(wù)端數(shù)據(jù)并打印
        new Thread(new Receive(client)).start();//一條路徑
    }
}

發(fā)送數(shù)據(jù)線程

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


/**
 * 發(fā)送數(shù)據(jù)  線程
 */
public class Send implements Runnable{
    //控制臺輸入流
    private BufferedReader console;
    //管道輸出流
    private DataOutputStream dos;
    //控制線程的標(biāo)識符
    private boolean isRunning = true;
    //名稱  不考慮重名
    private String name;
    //初始化建立管道
    public Send(Socket socket, String name) {
        try {
            console = new BufferedReader(new InputStreamReader(System.in));
            dos = new DataOutputStream(socket.getOutputStream());
            this.name = name;
            send(name);
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
            CloseUtil.closeAll(dos, console);
        }
    }

    
    /**
     * 1.從控制臺接收數(shù)據(jù)
     * 2.向服務(wù)端發(fā)送數(shù)據(jù)
     */
    //1.從控制臺接收數(shù)據(jù)
    private String getMsgFromConsole() {
        String msg = "";
        try {
            msg = console.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
            CloseUtil.closeAll(dos, console);
        }
        return msg;
    }
    //2.向服務(wù)端發(fā)送數(shù)據(jù)
    private void send(String msg) {
        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(getMsgFromConsole());
        }
    }
}

接收數(shù)據(jù)線程

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


public class Receive implements Runnable{
    //輸入流
    private DataInputStream dis;
    //線程標(biāo)識符
    private boolean isRunning = true;
    //初始化建立管道
    public Receive(Socket socket) {
        try {
            dis = new DataInputStream(socket.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
            CloseUtil.closeAll(dis);
        }
    }
    /**
     * 接收數(shù)據(jù)
     */
    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.關(guān)閉流工具類

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


/**
 * 關(guān)閉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();
            }
        }
    }
}
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號