基于socket的进程通信

  • 实现目标

    • 实现服务端与客户端的连接
    • 实现多个客户端向服务端发送消息,并由服务端将消息发送给每个客户端
  • 涉及的Java类

    • java.net.ServerSocket 用于创建服务器端口
    • java.net.Socket 用于创建Socket
    • java.net.URLDecoder 用于在服务端将客户端传来的消息解码
    • java.util.ArrayList 用于动态存放多个不同的Socket
    • Java.util.scanner 用于从控制台读取输入
  • 具体实现思路

    • 服务端

      • 在主函数中建立一个端口用于监听客户端请求,端口大小可自行设置

        ServerSocket sock = new ServerSocket(1999)
        
      • 需要接受多个客户端的消息,因此需要和每个客户端建立唯一的Socket对用于通信,所以需要将新建的Socket存入动态容器ArrayList

        ArrayList list = new ArrayList()
        
      • 使用while循环,在while循环中调用ServerSocket的accept()方法等待客户端请求,当接受到请求时就将返回的Socket存入容器中,并新建一个线程(调用start函数)

        while(true) {
            Socket socket = sock.accept();
            list.add(socket);
            new MsgThread(socket, list).start();
        }
        
      • 在线程类中进行数据的读入和输出

      • 定义类的属性:Socket, ArrayList,BufferedReader

      • 定义构造函数,将传入的参数赋给当前对象的属性,同时,通过Socket读取客户端的数据到BufferedReader对象

        BufferedReader bf = new BufferedReader(new   InputStreamReader(client.getInputStream));
        //这里需要用InputStreamReader类来包装client.getInputStream是为了将字节流转换成字符流
        
      • 重载run函数,将读取的消息发送给除当前socket对象外的其他客户端

        • 在这一步中的PrintWriter的使用要注意,一定要将自动刷新设置为true,否则消息就不能够即时传入到内存中,而是会等到程序结束时才传入,这个bug卡了我好久
      • 将消息解码后显示在控制台上

    • 客户端

      • 和服务端差不多的思路,主要是实现消息的读取和上传

      • 新建Socket,连接服务端

        Socket client = new Socket("127.000.001", 1999;
        
      • 读取Socket中的数据并显示在控制台上

      • 线程函数和服务端类似,无非是从控制台读取数据然后用getOutPutStream写入Socket中

  • 源码

    //服务端
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.URLDecoder;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    
    public class ChatServer {
        //SockerList用于保存当前连接的用户
        public static ArrayList SocketList = new ArrayList();
        public static void main(String[] args) throws IOException {
            //创建端口监听用户的请求
            ServerSocket sock = new ServerSocket(1999);
            System.out.println("服务启动....");
            //服务器循环接受来自用户端的请求
            while(true) {
                //等待客户端的请求,捕获到请求后返会一个Socket
                Socket socket = sock.accept();
                System.out.println("服务连接....");
                //将返回的Socket加入在线用户列表中
                SocketList.add(socket);
                System.out.println("当前有" + (SocketList.size()) + "个用户");
                //创建一个新的线程,每个连接都会有自己独立的任务线程,用于实现接受和发送消息
                new MsgThread(socket, SocketList).start();
            }
        }
    }
    
    //任务线程
    class MsgThread extends Thread {
        //定义单个用户连接的Socket
        Socket client;
        //定义用户组的Socket
        ArrayList clients;
        //定义读入的数据
        BufferedReader br;
        //构造函数
        public MsgThread(Socket client, ArrayList clients) throws IOException {
            //调用父类的构造函数
            super();
            //使用传入的参数初始化
            this.client = client;
            this.clients = clients;
            //将当前用户的输入缓存
            br = new BufferedReader(new InputStreamReader(this.client.getInputStream()));
        }
        //重载run()函数,将接受到的用户信息发送给其他用户
        @Override
        public void run() {
            try {
                String content = null;
                while(true) {
                    //从某个客户端获取信息
                    if ((content = br.readLine()) != null) {
                        //将消息发送给其他各个客户端
                        for (Socket socket:clients) {
                            //去掉自身客户端
                            if (socket != client) {
                                //将消息写入socket的缓存区,设置为自动刷新
                                PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
                                pw.println(content);
                            }
                        }
                        content = URLDecoder.decode(content, "UTF-8");
                        System.out.println(content);
                    }
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    //客户端
    import java.io.*;
    import java.net.*;
    
    public class ChatClient {
    
        public static void main(String[] args) throws Exception {
            //连接服务端
            Socket client = new Socket("127.0.0.1", 1999);
            System.out.println("服务器已连接");
            //新建线程
            new MsgThread(client).start();
            //获取输入
            InputStream in = client.getInputStream();
            BufferedReader bf = new BufferedReader(new InputStreamReader(in));
            while (true) {
                String msg = bf.readLine();
                //对收到的信息进行解码
                msg=URLDecoder.decode(msg, "UTF-8");
                System.out.println(msg);
            }
        }
    }
    
    class MsgThread extends Thread {
        Socket client;
        String hostname;
        public MsgThread(Socket client) {
            super();
            this.client = client;
            try {
                //获取本计算机名称
                InetAddress addr = InetAddress.getLocalHost();
                hostname =addr.getHostName().toString();
            } catch (UnknownHostException e1) {
                e1.printStackTrace();
            }
        }
        //发送消息
        @Override
        public void run() {
            try {
                //读取控制台输入
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                //将客户端输出流存到pw中
                PrintWriter pw = new PrintWriter(client.getOutputStream(),true);
                while (true) {
                    String msg = br.readLine();
                    //对发出的消息进行编码
                    msg = URLEncoder.encode(hostname + "说:"+ msg, "UTF-8");
                    pw.println(msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    

你可能感兴趣的:(基于socket的进程通信)