java socket 线程池echo服务器

java socket系列文章
java socket 单线程echo服务器
java socket 多线程echo服务器
java socket 线程池echo服务器

java socket 多线程echo服务器这篇文章中,改善了单线程echo服务器中只能处理一个客户端请求的弊端,利用一个客户端对应一个线程的方法,达到处理多个客户端的目的。

但是,每个新线程都会消耗系统资源:

  1. 创建一个线程会占用 CPU 周期,而且每个线程都会建立自己的数据结构(如,栈),也要消耗系统内存。
  2. 当一个线程阻塞时,JVM 将保存其状态,选择另外一个线程运行,并在上下文转换(context switch)时恢复阻塞线程的状态。随着线程数的增加,线程将消耗越来越多的系统资源,这将最终导致系统花费更多的时间来处理上下文转换盒线程管理,更少的时间来对连接进行服务。

在这种情况下,加入一个额外的线程实际上可能增加客户端总服务的时间。当线程数目过多的时候,必然导致每个客户端请求的处理时间增长,使用户体验明显变差。

我们可以通过限制线程总数并重复使用线程来避免这个问题。我们让服务器在启动时创建一个由固定线程数量组成的线程池,线程池的工作原理:

  1. 当一个新的客户端连接请求传入服务器,它将交给线程池中的一个线程处理,
  2. 该线程处理完这个客户端之后,又返回线程池,继续等待下一次请求。
  3. 如果连接请求到达服务器时,线程池中所有的线程都已经被占用,它们则在一个队列中等待,直到有空闲的线程可用。

与一客户一线程服务器一样,线程池服务器首先创建一个 ServerSocket 实例。
然后创建 N 个线程,每个线程反复循环,从(共享的)ServerSocket 实例接收客户端连接。当多个线程同时调用一个 ServerSocket 实例的 accept()方法时,它们都将阻塞等待,直到一个新的连接成功建立,然后系统选择一个线程,为建立起的连接提供服务,其他线程则继续阻塞等待。
线程在完成对一个客户端的服务后,继续等待其他的连接请求,而不终止。如果在一个客户端连接被创建时,没有线程在 accept()方法上阻塞(即所有的线程都在为其他连接服务),系统则将新的连接排列在一个队列中,直到下一次调用 accept()方法。

客户端代码:
public class Client {
    public static void main(String[] args) throws IOException {      
        Socket client = new Socket("127.0.0.1", 20012);  
        //客户端请求与本机在20011端口建立TCP连接 
        client.setSoTimeout(10000);             
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 
        //获取键盘输入        
        PrintStream out = new PrintStream(client.getOutputStream());          
        //获取Socket的输出流,用来发送数据到服务端                  
        BufferedReader buf =  new BufferedReader(new InputStreamReader(client.getInputStream()));  
        //获取Socket的输入流,用来接收从服务端发送过来的数据 
        boolean flag = true;  
        while(flag){  
            System.out.print("输入信息:");  
            String str = input.readLine();  
            out.println(str);  
            //发送数据到服务端   
            if("bye".equals(str)){  
                flag = false;  
            }else{  
                try{  
                    //从服务器端接收数据有个时间限制(系统自设,也可以自己设置),超过了这个时间,便会抛出该异常  
                    String echo = buf.readLine();  
                    System.out.println(echo);  
                }catch(SocketTimeoutException e){  
                    System.out.println("Time out, No response");  
                }  
            }  
        }  
        input.close();  
        if(client != null){  
            //如果构造函数建立起了连接,则关闭套接字,如果没有建立起连接,自然不用关闭  
            client.close(); //只关闭socket,其关联的输入输出流也会被关闭  
        }  
    }  
}

服务器端代码
public class ThreadPoolServer {
    public static void main(String[] args) {
        ServerSocket server;
        ExecutorService executor=Executors.newFixedThreadPool(2);
        try {
            server = new ServerSocket(20012);
               Socket client = null;
                while(true){ 
                    System.out.println("服务器端等待客户端发起连接请求");     
                    client = server.accept();
                    System.out.println("客户端向服务器端发起了连接请求,且连接成功");
                    executor.execute(new Handler(client));                 
                }
        } catch (IOException e) {
            e.printStackTrace();
        }  
    }
}

线程处理代码
public class Handler extends Thread{
    private Socket client; 
    PrintStream out;
    BufferedReader buf;
    public Handler(Socket client){
        this.client = client; 
        try {
            out = new PrintStream(client.getOutputStream());
            buf = new BufferedReader(new InputStreamReader(client.getInputStream())); 
            
        } catch (IOException e) {
            e.printStackTrace();
        }               
    } 
    public void run(){
         try{  
             boolean flag =true;  
             while(flag){                
                 String str =  buf.readLine();  
                 if(str == null || "".equals(str)){  
                     flag = false;  
                 }else{  
                     if("bye".equals(str)){  
                         flag = false;  
                     }else{  
                        System.out.println("服务器从客户端接受到的数据:"+str);
                         out.println("echo:" + str);  
                     }  
                 }  
             }  
             out.close();  
             client.close();  
         }catch(Exception e){  
             e.printStackTrace();  
         }  
     }      
}

此项目的完整代码可以到我的github,java-socket进行下载。

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

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,236评论 11 349
  • java socket系列文章java socket 单线程echo服务器java socket 多线程ech...
    snoweek阅读 2,043评论 1 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • 早上,一一问候了几位我的VlP客户。作为服务人员,我们不能等着客户来找我们,而是要经常的去关心他们的工作,生活。...
    孙其花阅读 517评论 7 0
  • 小时候,觉得时间是一只透明的蝴蝶! 长大后,时间变成了一只凝视着你的黑猫!
    陈鲁方阅读 98评论 0 0