美文网首页
java socket 线程池echo服务器

java socket 线程池echo服务器

作者: snoweek | 来源:发表于2016-03-26 10:30 被阅读768次

    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进行下载。

    相关文章

      网友评论

          本文标题:java socket 线程池echo服务器

          本文链接:https://www.haomeiwen.com/subject/wuedlttx.html