• Java-->实现群聊功能(C/S模式--TCP协议)


    --> Java 对TCP协议的支持:

    --> java.net包中定义了两个类ServerSocket 和Socket ,分别用来实现双向连接的server 端和client 端。

    --> Client 类定义客户端

    package com.dragon.java.tcpchat;
    
    import java.io.IOException;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    /**
     * 客户端
     * 
     * @author Auser
     * 
     */
    public class Client {
        public static void main(String args[]) throws UnknownHostException,
                IOException {
            Socket client = new Socket("192.168.1.188", 10000);
    
            // 穿件发送信息的线程
            new ClientSend(client).start();
            // 创建接收信息的线程
            new ClientReceive(client).start();
    
         // 因为要实现聊天功能,而不是只发送一次信息,所以输出流和客户端都不能关闭。
    // client.shutdownOutput(); // client.close(); } }

    --> ClientSend 类 定义客户端向服务端发送信息的线程

    package com.dragon.java.tcpchat;
    
    import java.io.IOException;
    import java.io.PrintStream;
    import java.net.Socket;
    import java.util.Scanner;
    
    /**
     * 客户端向服务端发送信息的线程
     * 
     * @author Auser
     * 
     */
    public class ClientSend extends Thread {
        private Scanner scanner;
        private Socket socket;
    
        public ClientSend(Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            scanner = new Scanner(System.in);
    
            try {
                PrintStream ps = new PrintStream(socket.getOutputStream());
                String line = "";
                // 阻塞式发送信息
                while ((line = scanner.nextLine()) != null) {
                    ps.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    --> ClientReceive 类 定义客户端接收服务端信息的线程

    package com.dragon.java.tcpchat;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.Socket;
    
    /**
     * 客户端接收信息的线程
     * 
     * @author Auser
     * 
     */
    public class ClientReceive extends Thread {
        private Socket socket;
    
        public ClientReceive(Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                // 按行接收信息
                String line = "";
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

    --> Server 类定义服务端

    package com.dragon.java.tcpchat;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 服务器
     * 
     * @author Auser
     * 
     */
    public class Server {
        public static void main(String[] args) throws IOException,
                InterruptedException {
            List<Socket> list = new ArrayList<>();
    
            // 创建服务器端的套接字
            ServerSocket server = new ServerSocket(10000);
    
            while (true) {
                // 接收客户端的阻塞方法
                Socket socket = server.accept();
                // 设计到多个线程可能会对集合进行增删的操作,要进行同步的处理
                synchronized (list) {
                    list.add(socket);
                }
                // 启动一个新的线程去处理这个客户端的交流
                new HandleSocket(socket, list).start();
            }
         // 因为不知道客户端什么时候发送信息,所以服务端要一直开启不能关闭。
        }
    }

    --> HandleSocket 类对连接到服务端的客户端进行操作(上下线通知、屏蔽拉黑、将信息发送到每个客户端等...)

    package com.dragon.java.tcpchat;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.util.List;
    
    /**
     * 处理每个(单个)连接到服务器的客户端的线程
     * 
     * @author Auser
     * 
     */
    public class HandleSocket extends Thread {
    
        private Socket socket;
        private List<Socket> list;
    
        /**
         * 构造方法
         * 
         * @param socket
         *            当前连接的客户端
         * @param list
         *            存储已连接客户端的集合
         */
        public HandleSocket(Socket socket, List<Socket> list) {
            this.socket = socket;
            this.list = list;
        }
    
        /**
         * 线程run方法
         */
        @Override
        public void run() {
            InetAddress address = socket.getInetAddress(); // 获取连接到服务器的这的客户端的地址
            String ip = address.getHostAddress();
            System.out.println(ip + "上线了!");
            if (ip.equals("192.168.1.117")) {
                synchronized (list) {
                    sendToAll(ip + "由于违规操作,已被拉入黑名单!");
                    list.remove(socket);
                }
                return;
            }
    
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        socket.getInputStream(), "gbk"));
    
                String line = "";
                while ((line = br.readLine()) != null) {
                    String msg = ip + ":" + line;
                    System.out.println(msg); // 输出到服务器端的控制台
                    // 把这个客户端说的话,发给其他所有的客户端
                    sendToAll(msg);
                }
    
            } catch (IOException e) {
                // e.printStackTrace();
                System.out.println(ip + "下线了!");
                synchronized (list) {
                    list.remove(socket);
                }
            }
        }
    
        /**
         * 把信息发送给所有的客户端,去除当前socket
         * 
         * @param msg
         *            发送的信息
         */
        private void sendToAll(String msg) {
            synchronized (list) {
                for (Socket s : list) {
                    if (s != socket) {
                        try {
                            PrintStream ps = new PrintStream(s.getOutputStream());
                            ps.println();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
    }

    --> 注意:因为要实现客户端连接到服务端,即客户端要先找到服务端,所以服务端要先开启,再开启服务端...

    --> 这是一个弱小的局域网群聊功能...

  • 相关阅读:
    php的序列化和反序列化有什么好处?
    解析PHP多种序列化与反序列化的方法
    PHP 数组和字符串互相转换实现方法
    PHP中foreach()用法汇总
    php实现伪静态的方法
    PHP中如何定义类及其成员属性与操作
    单例模式优缺点
    PHP 单例模式解析和实战
    主从复制之莫名少表
    诡异的 ERROR 1045 (28000): Access denied for user 错误
  • 原文地址:https://www.cnblogs.com/xmcx1995/p/5793879.html
Copyright © 2020-2023  润新知