美文网首页
Java Socket

Java Socket

作者: sunpy | 来源:发表于2018-08-12 18:31 被阅读13次
    风景c.jpg

    什么是套接字Socket

    Socket本身就是网络上的两个程序可以互相发送请求和接收请求,应用程序可以利用套接字在网络上进行数据传输。
    Socket本身作为应用程序和网络层TCP/UDP之间的一个抽象层,在TCP中主要采用流套接字,采用的方式就是点对点通过字节流传输;UDP主要采用数据报套接字。

    面向连接的入门例子

    功能:客户端发送请求,服务器接收请求
    服务端:

    public class MyServer {
    
        class HandleTask {
            
            private Socket socket;
            
            public HandleTask() {}
    
            public HandleTask(Socket socket) {
                this.socket = socket;
            }
            
            public void handle() {
                StringBuilder sb = new StringBuilder("Hello: ");
                InputStream is = null;
                BufferedReader br = null;
                
                try {
                    is = socket.getInputStream();
                    br = new BufferedReader(new InputStreamReader(is));
                    sb.append(br.readLine());
                    System.out.println(sb.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (null != br) {
                            br.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    
                    try {
                        if (null != is) {
                            is.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                
                try {
                    Thread.sleep(15000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println(sb.toString() + "-- 结束执行 --");
            }
        }
        
        
        public static void main(String[] args) throws IOException{
            ServerSocket serverSocket = null;
            Socket socket = null;
            try {
                serverSocket = new ServerSocket(9999);
                while (true) {
                    socket = serverSocket.accept();
                    new MyServer().new HandleTask(socket).handle();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                if (null != socket) {
                    socket.close();
                }
                
                if (null != serverSocket) {
                    serverSocket.close();
                }
            }
        }
    }
    
    

    思路:
    ① 服务器端启动了ServerSocket,然后绑定了端口9999。
    ② 调用accept方法,阻塞等待客户端连接。
    ③ 当接收到客户端的请求之后,通过字节流获取客户端发来的信息。
    多个客户端:

    public class MyClient {
    
        public static void main(String[] args) {
            Socket socket = null;
            BufferedWriter bw = null;
            Scanner scanner = new Scanner(System.in);
            
            try {
                socket = new Socket("localhost", 9999);
                bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                bw.write(scanner.nextLine());
                bw.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                scanner.close();
                
                try {
                    if (null != bw) {
                        bw.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
                try {
                    if (null != socket) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public class MyClient2 {
    
        public static void main(String[] args) {
            Socket socket = null;
            BufferedWriter bw = null;
            Scanner scanner = new Scanner(System.in);
            
            try {
                socket = new Socket("localhost", 9999);
                bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                bw.write(scanner.nextLine());
                bw.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                scanner.close();
                
                try {
                    if (null != bw) {
                        bw.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
                try {
                    if (null != socket) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    结果:


    1.jpg

    解释:
    上面这个例子的缺陷就是如果是多个请求去等待服务器端去处理,那么服务器端会按照收到请求的顺序执行,这样如果第一个请求执行时间很长,那么第二个请求就很长时间等不到执行。

    多线程执行多个客户端

    场景
    基于上面的例子,思考:服务器在很多情况下是需要接收来自很多个客户端的请求的。
    解决办法
    根据多线程时间分片方式来解决问题:多个客户端的请求,那么服务器采用每次接收到一个请求就创建一个线程来执行。
    采用多线程改进的服务端

    public class MyThreadServer {
        
        class HandleTask extends Thread{
    
            private Socket socket;
            public HandleTask() {}
    
            public HandleTask(Socket socket) {
                this.socket = socket;
            }
            
            @Override
            public void run() {
                StringBuilder sb = new StringBuilder("Hello: ");
                InputStream is = null;
                BufferedReader br = null;
                
                try {
                    is = socket.getInputStream();
                    br = new BufferedReader(new InputStreamReader(is));
                    sb.append(br.readLine());
                    System.out.println(sb.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (null != br) {
                            br.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    
                    try {
                        if (null != is) {
                            is.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                
                try {
                    Thread.sleep(15000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println(sb.toString() + "-- 结束执行 --");
            }
        }
        
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            Socket socket = null;
            try {
                serverSocket = new ServerSocket(9999);
                while (true) {
                    socket = serverSocket.accept();
                    new MyThreadServer().new HandleTask(socket).start();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                try {
                    if (null != socket) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
                try {
                    if (null != serverSocket) {
                        serverSocket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    2.jpg
    3.jpg

    方案使用的模型:
    上面的程序专门使用一个接收者线程来专门负责监听客户端的请求,接收到客户端的请求,就为其创建一个新的线程去执行业务处理,最后通过字节流进行返回响应。这种模型就是BIO(阻塞IO)。
    方案的缺点:
    这种工作的模型有一个问题,就是当请求数很多时,就会创建和请求数一样多匹配线程。最终当并发量上来,那么系统的性能将会下降。

    线程池执行多个客户端

    场景:
    基于上面的例子,使用多线程方式来处理请求,每个请求都创建一个匹配的线程,浪费线程资源。采用线程池管理线程,可以充分利用线程。
    采用线程池改进的服务端:

    public class MyThreadPoolServer {
    
        private static ExecutorService es = Executors.newCachedThreadPool();
        
        class HandleTask extends Thread {
    
            private Socket socket;
            public HandleTask() {}
    
            public HandleTask(Socket socket) {
                this.socket = socket;
            }
            
            @Override
            public void run() {
                StringBuilder sb = new StringBuilder("Hello: ");
                InputStream is = null;
                BufferedReader br = null;
                
                try {
                    is = socket.getInputStream();
                    br = new BufferedReader(new InputStreamReader(is));
                    sb.append(br.readLine());
                    System.out.println(sb.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (null != br) {
                            br.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    
                    try {
                        if (null != is) {
                            is.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                
                try {
                    Thread.sleep(15000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println(sb.toString() + "-- 结束执行 --");
            }
        }
        
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            Socket socket = null;
            try {
                serverSocket = new ServerSocket(9999);
                while (true) {
                    socket = serverSocket.accept();
                    es.execute(new MyThreadServer().new HandleTask(socket));
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                try {
                    if (null != socket) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
                try {
                    if (null != serverSocket) {
                        serverSocket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    4.jpg

    方案使用的模型:


    5.jpg

    相关文章

      网友评论

          本文标题:Java Socket

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