基于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<Socket>中

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

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

      • 定义类的属性:Socket, ArrayList<Socket>,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<Socket> SocketList = new ArrayList<Socket>();
        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<Socket> clients;
        //定义读入的数据
        BufferedReader br;
        //构造函数
        public MsgThread(Socket client, ArrayList<Socket> 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();
            }
        }
    }
    
    
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容