Java实现---局域网聊天

聊天室实现是通过C/S架构实现,既要有服务器端,也要有客户端。
实现原理:
      (1)服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
      (2)服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
      (3)服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
      (4)Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
      (5)在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
      (6)连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

客户端和服务器端要实现的类和方法:

C:客户端
         Socket类:
                 public Socket(String host,int port):绑定指定域名,端口号的服务器。

                 获取客户端输入流,读取服务器端发来的消息:
                 public InputStream getInputStream();
                 获取客户端输出流,向服务器端发送消息:
                 public OutputStream getOutputStream();

S:服务器端
         ServerSocket类:

                 建立起基站
                      public ServerSocket():无参构造,默认绑定本地IP。
                      public ServerSocket(int port):默认绑定本地IP127.0.0.1以及制定端口号。
                 等待连接:
                      public Socket accept():等待客户端连接,线程阻塞,当有客户端连接时,返回当有客户端socket。

                 当服务器与客户端建立起连接后,通过输入输出流(客户端的socket)来通信。
                      Socket提供的方法:
                             获取客户端输入流,读取客户端发来的消息:
                             public InputStream getInputStream();
                             获取客户端输出流,向客户端发送消息:
                             public OutputStream getOutputStream();

一.单线程版本聊天室:

服务器端:

public class SimpleServer {
    public static void main(String[] args) {
        try {

            //建立服务端ServerSocket并绑定本地端口号6666
            ServerSocket serverSocket=new ServerSocket(6666);
            //等待客户端连接
            System.out.println("等待客户端连接中");
            //服务器线程一直阻塞,直到有客户端连接,返回客户端连接Socket
            Socket client=serverSocket.accept();
            System.out.println("有客户端连接,客户端端口号为:"+client.getPort());

            //获取客户端输出流,向客户端输出信息:true:自动刷新
            PrintStream out=new PrintStream(client.getOutputStream(),true,"UTF-8");
            //获取客户端输入流,读取客户端信息
            Scanner in=new Scanner(client.getInputStream());
            if(in.hasNextLine())
            {
                System.out.println("客户端发来的信息"+in.nextLine());
            }
            out.println("holle I am Server");

            //关闭输入,输出流
            in.close();
            out.close();
            serverSocket.close();
        } catch (IOException e) {
            System.out.println("服务器端建立连接失败,异常为:"+e);
        }
    }
}

客户端:

public class SimpleCilent {
    public static void main(String[] args) {
        try {
            //建立客户端Socket并绑定服务器
            Socket client=new Socket("127.0.0.1",6666);
            //获取输出流向,服务器发送信息
            PrintStream out=new PrintStream(client.getOutputStream(),true,"UTF-8");
            out.println("Hi,I am client");

            //获取输入流,读取服务器发来的消息
            Scanner in=new Scanner(client.getInputStream());
            if(in.hasNextLine())
            {
                System.out.println("服务器发来的信息为:"+in.nextLine());
            }

            //关闭输入输出流
            in.close();
            out.close();
            client.close();
        } catch (IOException e) {
            System.out.println("客户端出现通信异常,异常为:"+e);
        }
    }
}

二.多线程版本的聊天室:

服务器端:


/*
多线程版本服务器端

 */
public class MultiThreadServer {
    //采用ConcurrentHashMap存储所有连接到服务器客户端信息,避免线程安全问题,效率高
    private static Map<String,Socket> clientMap=new ConcurrentHashMap<>();
    //采用内部类具体处理每个客户端请求,并且内部类可以访问外部类私有属性
    private static class ExeccuteRealClient implements  Runnable
    {
        /*
        服务器端功能:
            注册用户:userName:
            群聊:G:
            私聊:P:用户-
            用户退出:byebye
         */
        private Socket client;
        private ExeccuteRealClient(Socket client) {
            this.client = client;
        }
        @Override
        public void run() {
            try {
                //获取客户端输入流,读取用户发来的信息
                Scanner in=new Scanner(client.getInputStream());
                String str="";
                while(true)
                {
                    if(in.hasNextLine())
                    {
                        str=in.nextLine();
                        //识别Windows下的换行符,将/r换成空字符串
                        Pattern pattern=Pattern.compile("\r");
                        Matcher matcher=pattern.matcher(str);
                        matcher.replaceAll("");

                        //用户注册
                        if(str.startsWith("userName"))
                        {
                            //userName:test
                            String userName=str.split("\\:")[1];
                            userRegister(userName,client);
                            continue;
                        }

                        //群聊
                        if(str.startsWith("G"))
                        {
                            //G:123
                            String msg=str.split("\\:")[1];
                            GroupChat(msg);
                            continue;
                        }

                        //私聊
                        if(str.startsWith("P"))
                        {
                            //P:test-123
                            String userName=str.split("\\:")[1].split("\\-")[0];
                            String msg=str.split("\\:")[1].split("\\-")[1];
                            privateChat(userName,msg);
                            continue;
                        }

                        //退出
                        if(str.contains("byebye"))
                        {
                            //遍历Map,获取userName,根据V找K
                            String userName="";
                            for (String key:clientMap.keySet()) {
                                if(clientMap.get(key).equals(client)){
                                    userName=key;
                                }
                            }
                            System.out.println("用户"+userName+"下线了");
                            clientMap.remove(userName);
                            System.out.println("当前聊天室一共还有"+clientMap.size()+"人");
                            continue;
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //用户注册方法
        private static void userRegister(String userName,Socket socket)
        {
            System.out.println("用户"+userName+"上线了");
            //将用户保存在map中
            clientMap.put(userName,socket);
            System.out.println("当前聊天室一共有"+clientMap.size()+"人");
            try {
                //告知用户注册成功
                PrintStream out=new PrintStream(socket.getOutputStream());
                out.println("用户注册成功");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //群聊
        private static void GroupChat(String msg)
        {
            Set<Map.Entry<String,Socket>> clientSet=clientMap.entrySet();
            for (Map.Entry<String,Socket> entry:clientSet) {
                //遍历取出每个Socket
                Socket socket=entry.getValue();
                try {
                    //获取每个Socket的输出流
                    PrintStream out=new PrintStream(socket.getOutputStream());
                    out.println("群聊消息为:"+msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //私聊
        private static void privateChat(String userName,String msg)
        {
            //根据用户名获取指定Socket
            Socket socket=clientMap.get(userName);
            try {
                //获取指定socketde 输出流
                PrintStream out=new PrintStream(socket.getOutputStream());
                out.println("私聊消息:"+msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws Exception {
        //建立大小为20的线程:通过线程池
        ExecutorService executorService= Executors.newFixedThreadPool(20);
        //建立基站
        ServerSocket serverSocket=new ServerSocket(6666);
        for (int i = 0; i <20 ; i++) {
            System.out.println("等待客户端连接");
            Socket client=serverSocket.accept();
            System.out.println("有新的客户端连接,端口号为:"+client.getPort());
            //每当有用户连接,新建线程处理
            executorService.submit(new ExeccuteRealClient(client));
        }
        executorService.shutdown();
        serverSocket.close();
    }
}

客户端:


/*
客户端读取服务器发来信息线程
 */
class ReadFromServer implements  Runnable
{
    private Socket client;
    public ReadFromServer(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            Scanner in=new Scanner(client.getInputStream());
            while(true)
            {
                if(in.hasNextLine())
                {
                    System.out.println("从服务器发来的消息为:"+in.nextLine());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/*
向服务器发送信息
 */
class WriteToServer implements  Runnable
{
    private Socket client;
    public WriteToServer(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {

        try {
            //获取键盘输入流,读取用户从键盘发来的消息
            Scanner scanner=new Scanner(System.in);
            String string="";
            //获取客户端输出流,将用户键盘输入的消息发送给服务器
            PrintStream out=new PrintStream(client.getOutputStream(),true,"UTF-8");
            while(true)
            {
                System.out.println("请输入向服务器发送的信息:");
                if(scanner.hasNextLine())
                {
                    string=scanner.nextLine();
                    out.println(string);
                }

                //设置退出标致
                if(string.contains("beybey"))
                {
                    System.out.println("客户端退出,不聊了");
                    scanner.close();
                    out.close();
                    client.close();
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/*
多线程版本客户端
 */
public class MultiThreadClient {
    public static void main(String[] args) {
        try {
            Socket client=new Socket("127.0.0.1",6666);
            Thread readThread=new Thread(new ReadFromServer(client));
            Thread writeThread=new Thread(new WriteToServer(client));
            readThread.start();
            writeThread.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值