网络编程(六)聊天室代码实现

先写一个客户端输入数据,服务器端处理数据后返回给客户端

客户端:

​
public static void main(String[] args) throws UnknownHostException, IOException {

    Scanner sc = new Scanner(System.in);
    System.out.println("请客户端输入:");
    String msg = sc.nextLine();

    //创建客户端 指定服务器及端口 此时就在连接
    Socket client = new Socket("localhost",9999);

    //客户端输出数据 输出流
    DataOutputStream dos = new DataOutputStream(client.getOutputStream());
    dos.writeUTF(msg);
    dos.flush();

    //客户端读取数据, 输入流
    DataInputStream dis = new DataInputStream(client.getInputStream());
    msg = dis.readUTF();
    System.out.println(msg);

}

服务器端:

public static void main(String[] args) throws IOException {
    //创建服务器,指定端口
    ServerSocket server = new ServerSocket(9999);
    //接收客户端连接 阻塞式 该socket和客户端的socket是同一个socket
    Socket socket = server.accept();

    //服务器端读取数据, 输入流
    DataInputStream dis = new DataInputStream(socket.getInputStream());
    String msg = dis.readUTF();

    //服务器端输出数据 输出流
    DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
    dos.writeUTF(msg + " 服务器端输出");
    dos.flush();
}

启动服务器端后启动客户端:

请客户端输入:
你好

你好 服务器端输出

 

上述代码存在的问题,处理完一条数据就结束了,要想实现一直保持通信,加入死循环。输入流和输出流在同一个线程内 应该独立处理 彼此独立 引入多线程

服务器端:

public class ThreadServer {

    public static void main(String[] args) throws IOException {

        //创建服务器,指定端口
        ServerSocket server = new ServerSocket(9999);
        //接收客户端连接 阻塞式 该socket和客户端的socket是同一个socket
        Socket socket = server.accept();
        DataInputStream dis = new DataInputStream(socket.getInputStream());
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

        while(true){
        //服务器端读取数据, 输入流
        String msg = dis.readUTF();
        //服务器端输出数据 输出流
        dos.writeUTF(msg + " 服务器端输出");
        dos.flush();
        }
    }

}

客户端:

public class ThreadClient {

    public static void main(String[] args) throws UnknownHostException, IOException {

        //创建客户端 指定服务器及端口 此时就在连接
        Socket client = new Socket("localhost",9999);
        new Thread(new Send(client)).start(); //一条路径
        new Thread(new Receive(client)).start();//另一条路径
    } 
}

发送数据封装类:

public class Send implements Runnable{

    //输入数据 控制台
    private BufferedReader console; 
    //输出流
    private DataOutputStream dos;
    //是否running
    private boolean isRunning = true;

    public Send(Socket client){
        console = new BufferedReader(new InputStreamReader(System.in));
        try {
        dos = new DataOutputStream(client.getOutputStream());
        } catch (IOException e) {
            isRunning = false;
            CloseUtil.closeAll(console,dos);
        }
    }

    //控制台接收数据
    public String getMsgFromClient(){
        try {
            return console.readLine();
        } catch (IOException e) {

        }
        return "";
    }

    //发送信息
    public void send(){
        String msg = getMsgFromClient();
        try {
            if(null != msg && !msg.equals("")){
                dos.writeUTF(msg);
                dos.flush();
            }
        } catch (IOException e) {
            isRunning = false;
            CloseUtil.closeAll(console,dos);
        }
    }

    @Override
    public void run() {

        while(isRunning){
            send();
        }
    }
}

接收数据封装类:

public class Receive implements Runnable{

    //输入流 读取数据
    private DataInputStream dis;
    //是否running
    private boolean isRunning = true;

    public Receive(Socket client){
        try {
            dis = new DataInputStream(client.getInputStream());
        } catch (IOException e) {
            isRunning = false;
            CloseUtil.closeAll(dis);
        }
    }

    //接收信息
    public String receive() {
        String msg = "";
        try {
            msg = dis.readUTF();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            isRunning = false;
            CloseUtil.closeAll(dis);
        }
        return msg;
    }

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

关闭流工具类:

public class CloseUtil {

    public static void closeAll(Closeable... io){
        for(Closeable temp : io){
            try {
                if(null != temp){
                temp.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

上述代码中只实现了一个客户端,自己发送的数据自己接收,想当与自己给自己发送数据

 

群发:

给所有客户端发送数据

在上述代码的基础上只需要修改服务器端的代码

public class ThreadServer {

    private List list = new ArrayList();

    public static void main(String[] args) throws IOException {

        new ThreadServer().start();
    }


    public void start() throws IOException{
        //创建服务器,指定端口
        ServerSocket server = new ServerSocket(9999);
        //接收客户端连接 阻塞式 该socket和客户端的socket是同一个socket
        while(true){
            Socket client = server.accept();
            MyChannel channel = new MyChannel(client);
            list.add(channel);
            new Thread(channel).start();
        }
    } 

    /**
     * 一个客户端 一条道路
     */
    private class MyChannel implements Runnable{

    private DataInputStream dis = null;
    private DataOutputStream dos = null;
    private boolean isRunning = true;

    public MyChannel(Socket client){
        try {
            dis = new DataInputStream(client.getInputStream());
            dos = new DataOutputStream(client.getOutputStream());
        } catch (IOException e) {
            isRunning = false;
            CloseUtil.closeAll(dis,dos);
            list.remove(this);
        }
    }

    /**
    * 获取数据
    * @return
    */
    private String receive(){

        String msg = "";
        try {
            msg = dis.readUTF();
        } catch (IOException e) {
            isRunning = false;
            CloseUtil.closeAll(dis);
            list.remove(this);
        }
        return msg;
    }

    /**
    * 发送数据
    * @param msg
    */
    private void send(String msg){
        try {
            if(null == msg || msg.equals("")){
                return;
            }
            dos.writeUTF(msg);
            dos.flush();
        } catch (IOException e) {
            isRunning = false;
            CloseUtil.closeAll(dos);
            list.remove(this);
        }
    }

    /**
    * 发送给其他客户端
    */
    private void sendOthers(){

        String msg = this.receive();
        for(MyChannel other : list){
            if(other == this){
                continue;
            }
            //发送给其他客户端
            other.send(msg);
        }
    }    

    @Override
    public void run() {

        while(isRunning){
            sendOthers();
        }
    }
   }
}

启动服务器端 然后启动多个客户端(多次run as  ThreadClient)发现,后面启动的客户端,发送的数据前面启动的客户端都会接收到

此处我启动了三个客户端

第一次启动的客户端 

网络编程(六)聊天室代码实现_第1张图片

第二次启动

第三次启动 

回头看第一次启动的界面 发现接受到了第二次和第三次的数据

回头看第二次启动的界面 发现接受到第三次的数据

 

自学笔记,多有不足!!!

 

你可能感兴趣的:(网络编程)