java多线程服务器,实现客户端间聊天

来源:互联网 发布:淘宝开发者平台 api 编辑:程序博客网 时间:2024/05/13 11:37

转载请注明出处:http://blog.csdn.net/htwhtw123/article/details/78762364
通过服务器中转消息,实现多客户端之间的对话。客户端输入格式为:接受消息的客户端编号+空格+要发出的消息。客户端输入end下线。有客户端上线或下线,服务器都会通知其他客户端情况。效果如下图:


1.服务端

服务端为连接上的每一个客户端,提供一个接受线程,监听接受消息,在向客户端发送消息时会临时开启一个发送线程。

import java.io.IOException;import java.io.InputStream;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.List;/** * Created by HeTingwei on 2017/12/9. * 多线程服务器,实现多客户端聊天 */public class Server {    List<ReceiveThread> receiveList = new ArrayList<>();//存放已连接客户端类    private final static int MESSAGE_SIZE = 1024;//每次允许接受数据的最大长度    int num = 0;//客户端编号    public static void main(String[] args) {        new Server();    }    //服务端处理逻辑    Server() {        ServerSocket serverSocket = null;        try {            serverSocket = new ServerSocket(45678);//用来监听的套接字,指定端口号            while (true) {                Socket socket = serverSocket.accept();//监听客户端连接,阻塞线程                System.out.println("连接上客户端:" + num);//在其他线程处理接收来自客户端的消息                ReceiveThread receiveThread = new ReceiveThread(socket, num);                receiveThread.start();                receiveList.add(receiveThread);                //有客户端新上线,服务器就通知其他客户端                String notice="有新客户端上线,现在在线客户端有:客户端:";                for (ReceiveThread thread : receiveList) {                    notice = notice + "" + thread.num;                }                for (ReceiveThread thread : receiveList) {                    new SendThread(thread.socket, notice).start();                }                num++;            }        } catch (IOException e) {            e.printStackTrace();        }    }    //接受消息的线程(同时也有记录对应客户端socket的作用)    class ReceiveThread extends Thread {        int num;        Socket socket;//客户端对应的套接字        boolean continueReceive = true;//标识是否还维持连接需要接收        public ReceiveThread(Socket socket, int num) {            this.socket = socket;            this.num = num;            try {                //给连接上的客户端发送,分配的客户端编号的通知                socket.getOutputStream().write(("你的客户端编号是" + num).getBytes());            } catch (IOException e) {                e.printStackTrace();            }        }        @Override        public void run() {            super.run();            //接收客户端发送的消息            InputStream inputStream = null;            try {                inputStream = socket.getInputStream();                byte[] b;                while (continueReceive) {                    b = new byte[MESSAGE_SIZE];                    inputStream.read(b);                    b = splitByte(b);//去掉数组无用部分                    //发送end的客户端断开连接                    if (new String(b).equals("end")) {                        continueReceive = false;                        receiveList.remove(this);                        //通知其他客户端                        String message = "客户端" + num + "连接断开\n" +                                "现在在线的有,客户端:";                        for (ReceiveThread receiveThread : receiveList) {                            message = message + " " + receiveThread.num;                        }                        System.out.println(message);                        for (ReceiveThread receiveThread : receiveList) {                            new SendThread(receiveThread.socket, message).start();                        }                    } else {                        try {                            String[] data = new String(b).split(" ", 2);//以第一个空格,将字符串分成两个部分                            int clientNum = Integer.parseInt(data[0]);//转换为数字,即客户端编号数字                            //将消息发送给指定客户端                            for (ReceiveThread receiveThread : receiveList) {                                if (receiveThread.num == clientNum) {                                    new SendThread(receiveThread.socket, "客户端"+num+"发消息:"+data[1]).start();                                    System.out.println("客户端" + num + "发送消息到客户端" + receiveThread.num + ": " + data[1]);                                }                            }                        } catch (Exception e) {                            new SendThread(socket, "输入错误,请重新输入").start();                            System.out.println("客户端输入错误");                        }                    }                }            } catch (IOException e) {                e.printStackTrace();            } finally {                try {//关闭资源                    if (inputStream != null) {                        inputStream.close();                    }                    if (socket != null) {                        socket.close();                    }                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }    //发送消息的线程    class SendThread extends Thread {        Socket socket;        String str;        public SendThread(Socket socket, String str) {            this.socket = socket;            this.str = str;        }        @Override        public void run() {            super.run();            try {                socket.getOutputStream().write(str.getBytes());            } catch (IOException e) {                e.printStackTrace();            }        }    }    //去除byte数组多余部分   private   byte[] splitByte(byte b[]) {        int i = 0;        for(;i<b.length;i++) {            if (b[i] == 0) {                break;            }        }        byte[] b2 = new byte[i];        for (int j = 0; j <i ; j++) {            b2[j] = b[j];        }        return b2;    }}

2.客户端

在主线程中接受键盘输入,并发送消息,在子线程中接受消息。

import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.util.Scanner;/** * Created by HeTingwei on 2017/12/9. * 多线程客户端 */public class Client {    Socket socket;    private static final int MESSAGE_SIZE = 1024;//每次允许接受数据的最大长度    public static void main(String[] args) {        new Client();    }    public Client() {        try {            socket = new Socket("127.0.0.1", 45678);            if (socket.isConnected() == true) {                System.out.println("连接成功");                new Thread() {//开启一个接受数据的线程                    @Override                    public void run() {                        super.run();                        InputStream in;                        try {                            in = socket.getInputStream();                            byte[] b;                            while (true) {                                b = new byte[MESSAGE_SIZE];                                in.read(b);                                System.out.println("接收到服务端消息:" + new String(b));                            }                        } catch (IOException e) {                            e.printStackTrace();                        }                    }                }.start();            }            OutputStream out = null;            while (true) {                Scanner scanner = new Scanner(System.in);                String str = scanner.nextLine();                out = socket.getOutputStream();                out.write(str.getBytes());                out.flush();                if (str.equals("end")) {                    System.exit(0);//关闭客户端                }            }        } catch (IOException e) {            e.printStackTrace();        }    }}
原创粉丝点击