简单聊天室(java版)

来源:互联网 发布:go桌面软件下载 编辑:程序博客网 时间:2024/04/30 03:00
 这是本人从其他地方学习到的关于聊天室的一个模本,我从中截取了一部分关于客户端和服务端通信的Socket的内容。希望对大家对socket有个了解,我写的这些代码可以实现两人或多人在多台电脑上实现简单的对话。在运行时要先运行server(服务端),再运行client(客户端)。Windows获取自己电脑的ip需要再DOS(命令窗口)界面输入ipconfig或者再网络和共享中心已连接的网络查看详细信息。具体的代码如下

客户端代码

 package talkRoom;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.Socket;import java.util.Scanner;/** * 客户端 * @author ylg * */public class Client {    //客户端用于与服务端通信的socket    private Socket socket;    /**     *初始化客户端相关内容     */    public Client(){        try {            /**             * 实例化socket的过程就是连接的过程通常我们要传入两个参数             * 1:字符串,服务器的IP地址             * 2:整数,服务器端申请的端口号             * (serversocket创建时申请的端口号:8088)             */            System.out.println("尝试连接");            //此处的localhost可以改为运行服务端的那台电脑的的ip地址这样就可以连在一起聊天了            //localhost指的是本机的ip            socket =new Socket("localhost", 8088);            System.out.println("连接成功");        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 客户端用于交互的方法     */    public void start(){        try {            /**             * 创建一个线程,用于读取服务器发过来的信息             */            Runnable hander=new GetMessageFromServerHandler();            Thread t=new Thread(hander);            t.start();            /**             * 客户端想向服务发送消息,通过socket花去输出流之后写出数据即可             */            OutputStream out=socket.getOutputStream();            /**             * 向服务器发送字符串,我们可以将字节流转换为缓冲字符流输出PrintWrint             *              */            OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8");            /**             * 发送一个字符串就应当立即写出,所以要自动行刷新             */            PrintWriter pw=new PrintWriter(osw,true);            /**             * 创建scanner,将控制台输入的字符串通过pw发送给服务器             */            String message=null;            Scanner scanner=new Scanner(System.in);            while(true){                message=scanner.nextLine();                pw.println(message);            }        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {          Client client=new Client();          client.start();    }    /**     * 该线程的作用是让客户端可以读取服务器发送过来的信息     * @author ylg     *     */    class GetMessageFromServerHandler implements Runnable{        /**         * 通过socket获取输入流,在转换为缓冲字符输入流         * 最后通过循环都读取服务端发送的每一行信息         */        public void run() {            try {                InputStream in=socket.getInputStream();                InputStreamReader isr=new InputStreamReader(in,"utf-8");                BufferedReader br=new BufferedReader(isr);                String message=null;                while((message=br.readLine())!=null){                    System.out.println(message);                }            } catch (Exception e) {            }        }    }}

服务端代码(请先运行服务端)


package talkRoom;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 服务端 * @author ylg * */public class Server {    /**     * 用于与客户端连接的ServerSOocket     */    private ServerSocket server;    /**     * 存放所有客户端的输入流,用于广播信息     */    private List<PrintWriter> allOut;    /**     * 线程池,用于控制服务端线程数量,并重用线程     */    private ExecutorService threadPool;    /**     * 构造方法,用于初始化服务器相关内容     *      */    public Server(){        try {            //初始化ServerSocket            /**             * 初始化时要求我们传入一个整数,这个整数表示端口号,客户端就是             * 通过这个端口号连接到服务端的             */            server=new ServerSocket(8088);            /**             * 初始化存放所有客户端输出流的家集合             */            allOut =new ArrayList<PrintWriter>();            //初始化线程池            threadPool=Executors.newFixedThreadPool(50);        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 将给定的输出流存入共享集合中     * @param out     */    private synchronized void addOut(PrintWriter out){        allOut.add(out);    }    /**     * 从共享集合中删除给定的删除流     * @param out     */    private synchronized void removeOut(PrintWriter out){        allOut.remove(out);    }      //还要遍历方法,并且三个操作集合的方法互斥     /**      * 遍历所有的输出流将给定的字符串发送给所有客户端      * @param message 服务器接收到的消息      */    private synchronized void sendMsgToAllClient(String message){        for(PrintWriter pw:allOut){            pw.println(message);        }    }    /**     * 服务端开始工作的方法     */    public void start(){        try {            /**             * socket accept()             * 该方法是一个阻塞方法,用于等待客户端的连接             * 一旦一个客户端连接上,该方法就会返回与该客户端通信socket             */            System.out.println("等待客户端的连接...");            /**             * 死循环的目的是一直监听不同客户端的连接             */            while(true){                Socket socket=server.accept();                System.out.println("一个客户端连接上了...");                /**                 * 当一个客户端连接后,启动一个线程,将该客户端的socket传入,                 * 是该线程与客户端通信                 */                Runnable clientHandler=new ClientHandler(socket);//              Thread t=new Thread(clientHandler);//              t.start();                threadPool.execute(clientHandler);            }         } catch (Exception e) {        }finally {        }    }    public static void main(String[] args) {        Server server =new Server();        server.start();    }    /**     * 该线程的作用是与给定的客户端Socket进行通信     * @author ylg     *     */    class ClientHandler implements Runnable{        /**         * 当前线程用于交流的指定客户端的Socket         */        private Socket socket;        /**         * 创建线程体时将交互的Socket传入         * @param socket         */        public ClientHandler(Socket socket){            this.socket=socket;        }        /**         * 定义在try外面是因为finally中要引用         */        PrintWriter pw=null;        public void run(){            try {                /**                 * 通过socket获取输出流,用于将信息发送给客户端                 */                OutputStream out=socket.getOutputStream();                OutputStreamWriter osw=new OutputStreamWriter(out, "utf-8");                pw=new PrintWriter(osw,true);                /**                 * 将该客户端的输出流存入共享集合                 */                addOut(pw);                /**                 * 通过连接上的客户端的socket获取输入流来读取客户端发送过来的信息                 */                InputStream in=socket.getInputStream();                InputStreamReader isr=new InputStreamReader(in,"UTF-8");                /**                 * 包装为缓冲流字符输入流,可以按行读取字符串                 */                BufferedReader br=new BufferedReader(isr);                String message=null;                while((message=br.readLine())!=null){                    //将当前的发送的消息广播给所有客户端                    sendMsgToAllClient(message);                /*  //System.out.println("客户端说: "+message);                     //将读取到的信息发送给客户端                    pw.println(message);*/                    //在服务端上显示                    System.out.println(message);                }            } catch (Exception e) {            }finally{                /**                 * linux客户端若断开连接,服务端会读取到null                 * windows的客户端断开连接,服务端会抛出异常                 * 所以finally是我们最后处理的最佳地点                 */                System.out.println("客户端下线");                /**                 * 当客户端断开后,将其输出流从共享集合中删除                 */                removeOut(pw);                /**                 * 输出在线人数                 */                System.out.println("当前在线人数"+allOut.size());                /**                 * 不同分别关闭输入流与输出流                 * 关闭socket即可,因为这两个流都是从socket获取的,就好比打电话                 * 我们最终挂断电话就自然断开了麦克风和听筒一样                 */                try {                    socket.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

看不懂的可以在下方留言

1 0