且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Java中网络编程之TCP协议

更新时间:2022-10-02 21:04:33

一、TCP的基本概念

TCP是专门设计用于在不可靠的英特网上提供可靠的、端到端的字节流通信的协议,是一个面向连接的协议,TCP连接是字节流而非报文流。UDP和TCP各有65536个端口号互不影响。

 

二、单线程服务端

以下代码只能实现服务端和客户端的同步对话。服务端处理完一个客户端请求,才会处理另一个客户端请求。服务器端的输出效果是Client1阻塞20秒,Client2不会执行。必须等Client1阻塞结束之后,Client2才会执行。该例子可用来学习TCP的基本语法。


  1. /**  
  2.  * TCP客户端1  
  3.  *   
  4.  * @author 徐越  
  5.  *   
  6.  */ 
  7. public class Client1  
  8. {  
  9.     public static void main(String[] args) throws Exception  
  10.     {  
  11.         Socket socket = new Socket("127.0.0.1"8821);  
  12.         OutputStream os = socket.getOutputStream();  
  13.         String msg = "我是徐越1";  
  14.         Thread.sleep(20000);  
  15.         os.write(msg.getBytes());  
  16.         os.flush();  
  17.         os.close();socket.close();    
  18.     }  
  19. }  
  20.  
  21.  
  22. /**  
  23.  * TCP客户端2  
  24.  *   
  25.  * @author 徐越  
  26.  *   
  27.  */ 
  28. public class Client2  
  29. {  
  30.     public static void main(String[] args) throws Exception  
  31.     {  
  32.         Socket socket = new Socket("127.0.0.1"8821);  
  33.         OutputStream os = socket.getOutputStream();  
  34.         String msg = "我是徐越2";  
  35.         os.write(msg.getBytes());  
  36.         os.flush();  
  37.         os.close();socket.close();    
  38.     }  
  39. }  
  40.  
  41. /**  
  42.  * 单线程TCP服务端  
  43.  *   
  44.  * @author 徐越  
  45.  *   
  46.  */ 
  47. public class Server  
  48. {  
  49.     public static void main(String[] args) throws Exception  
  50.     {  
  51.         // 创建端口为8821的TCP服务器端对象  
  52.         // 8821是服务器端的端口号而客户端从某端口A连到8821,端口A是随机的  
  53.         ServerSocket serverSocket = new ServerSocket(8821);  
  54.         while (true)  
  55.         {  
  56.             // 若无客户端发送请求则线程在此阻塞,方法不继续执行  
  57.             Socket socket = serverSocket.accept();  
  58.             System.out.println("connected");  
  59.             InputStream instream = socket.getInputStream();  
  60.             ByteArrayOutputStream bos = new ByteArrayOutputStream();  
  61.             int len = 0;  
  62.             byte[] buffer = new byte[1024];  
  63.             while ((len = instream.read(buffer)) != -1)  
  64.             {  
  65.                 bos.write(buffer, 0, len);  
  66.             }  
  67.             instream.close();  
  68.             bos.flush();  
  69.             bos.close();  
  70.             String msg = bos.toString();  
  71.             System.out.println("客户端的IP:" + socket.getInetAddress().getHostAddress());  
  72.             System.out.println("客户端的端口:" + socket.getPort());  
  73.             System.out.println("客户端的信息:" + msg);  
  74.         }  
  75.     }  

执行结果

connected
客户端的IP:127.0.0.1
客户端的端口:3775
客户端的信息:我是徐越1
connected
客户端的IP:127.0.0.1
客户端的端口:3787
客户端的信息:我是徐越2

 

三、多线程服务器

在实际应用中是在服务器上运行一个永久的程序,接收来自其他多个客户端的请求,提供相应的服务。需要利用多线程实现多客户机制。服务器在指定的端口上监听是否有客户请求,一旦监听到就会启动一个专门的服务线程来响应该请求,而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。只要将服务端为如下代码,Client1和Client2就会异步执行。

 


  1. /**  
  2.  * 多线程服务端0  
  3.  *   
  4.  * @author 徐越  
  5.  *   
  6.  */ 
  7. public class MultiThreadServer0  
  8. {  
  9.     // 端口号  
  10.     private int port = 8821;  
  11.     // 服务端  
  12.     private ServerSocket serverSocket;  
  13.  
  14.     public MultiThreadServer0() throws IOException  
  15.     {  
  16.         // 创建服务器端  
  17.         serverSocket = new ServerSocket(port);  
  18.         System.out.println("服务器启动");  
  19.     }  
  20.  
  21.     public void service()  
  22.     {  
  23.         while (true)  
  24.         {  
  25.             Socket socket = null;  
  26.             try 
  27.             {  
  28.                 // 客户端进行连接时会触发accept方法从而建立连接  
  29.                 socket = serverSocket.accept();  
  30.                 new MultiThreadHandler(socket).start();  
  31.             }  
  32.             catch (Exception e)  
  33.             {  
  34.                 e.printStackTrace();  
  35.             }  
  36.         }  
  37.     }  
  38.  
  39.     public static void main(String[] args) throws IOException  
  40.     {  
  41.         new MultiThreadServer1().service();  
  42.     }  
  43. }  
  44.  
  45. /**  
  46.  * 多线程处理类  
  47.  */ 
  48. class MultiThreadHandler extends Thread  
  49. {  
  50.     private Socket socket;  
  51.  
  52.     public MultiThreadHandler(Socket socket)  
  53.     {  
  54.         this.socket = socket;  
  55.     }  
  56.  
  57.     private BufferedReader getReader(Socket socket) throws IOException  
  58.     {  
  59.         InputStream socketIn = socket.getInputStream();  
  60.         // InputStreamReader为转换流  
  61.         // InputStream本是字节流,现加一个Reader,表示用字符流的方式读取字节流  
  62.         InputStreamReader isr = new InputStreamReader(socketIn);  
  63.         return new BufferedReader(isr);  
  64.     }  
  65.  
  66.     public void run()  
  67.     {  
  68.         try 
  69.         {  
  70.             BufferedReader br = getReader(socket);  
  71.             String msg = null;  
  72.             while ((msg = br.readLine()) != null)  
  73.             {  
  74.                 System.out.println("客户端的IP:" + socket.getInetAddress().getHostAddress());  
  75.                 System.out.println("客户端的端口:" + socket.getPort());  
  76.                 System.out.println("客户端的信息:" + msg);  
  77.             }  
  78.         }  
  79.         catch (IOException e)  
  80.         {  
  81.             e.printStackTrace();  
  82.         }  
  83.         finally 
  84.         {  
  85.             try 
  86.             {  
  87.                 if (socket != null)  
  88.                 {  
  89.                     socket.close();  
  90.                 }  
  91.             }  
  92.             catch (IOException e)  
  93.             {  
  94.                 e.printStackTrace();  
  95.             }  
  96.         }  
  97.     }  
  98. }  
  99.  
  100.  
  101. /**  
  102.  * 多线程服务端1  
  103.  */ 
  104. public class MultiThreadServer1  
  105. {  
  106.     // 端口号  
  107.     private int port = 8821;  
  108.     // 服务端  
  109.     private ServerSocket serverSocket;  
  110.     // 线程池  
  111.     private ExecutorService executorService;  
  112.     // 单个CPU线程池大小  
  113.     private final int POOL_SIZE = 10;  
  114.  
  115.     public MultiThreadServer1() throws IOException  
  116.     {  
  117.         // 创建服务器端  
  118.         serverSocket = new ServerSocket(port);  
  119.         // 获取当前系统的CPU数目  
  120.         int cpuNums = Runtime.getRuntime().availableProcessors();  
  121.         // 根据系统资源情况灵活定义线程池大小  
  122.         executorService = Executors.newFixedThreadPool(cpuNums * POOL_SIZE);  
  123.         System.out.println("服务器启动");  
  124.     }  
  125.  
  126.     public void service()  
  127.     {  
  128.         while (true)  
  129.         {  
  130.             Socket socket = null;  
  131.             try 
  132.             {  
  133.                 // 客户进行连接就会触发accept方法从而建立连接  
  134.                 socket = serverSocket.accept();  
  135.                 // 调用线程池操作  
  136.                 executorService.execute(new Handler(socket));  
  137.             }  
  138.             catch (Exception e)  
  139.             {  
  140.                 e.printStackTrace();  
  141.             }  
  142.         }  
  143.     }  
  144.  
  145.     public static void main(String[] args) throws IOException  
  146.     {  
  147.         new MultiThreadServer1().service();  
  148.     }  
  149.  
  150. }  
  151.  
  152. /**  
  153.  * 多线程处理类  
  154.  */ 
  155. class Handler implements Runnable  
  156. {  
  157.     private Socket socket;  
  158.  
  159.     public Handler(Socket socket)  
  160.     {  
  161.         this.socket = socket;  
  162.     }  
  163.  
  164.     private BufferedReader getReader(Socket socket) throws IOException  
  165.     {  
  166.         InputStream socketIn = socket.getInputStream();  
  167.         // InputStreamReader为转换流  
  168.         // InputStream本是字节流,现加一个Reader,表示用字符流的方式读取字节流  
  169.         InputStreamReader isr = new InputStreamReader(socketIn);  
  170.         return new BufferedReader(isr);  
  171.     }  
  172.  
  173.     public void run()  
  174.     {  
  175.         try 
  176.         {  
  177.             BufferedReader br = getReader(socket);  
  178.             String msg = null;  
  179.             while ((msg = br.readLine()) != null)  
  180.             {  
  181.                 System.out.println("客户端的IP:" + socket.getInetAddress().getHostAddress());  
  182.                 System.out.println("客户端的端口:" + socket.getPort());  
  183.                 System.out.println("客户端的信息:" + msg);  
  184.             }  
  185.         }  
  186.         catch (IOException e)  
  187.         {  
  188.             e.printStackTrace();  
  189.         }  
  190.         finally 
  191.         {  
  192.             try 
  193.             {  
  194.                 if (socket != null)  
  195.                 {  
  196.                     socket.close();  
  197.                 }  
  198.             }  
  199.             catch (IOException e)  
  200.             {  
  201.                 e.printStackTrace();  
  202.             }  
  203.         }  
  204.     }  

 两个多线程服务端执行结果相同

服务器启动
客户端的IP:127.0.0.1
客户端的端口:3931
客户端的信息:我是徐越2
客户端的IP:127.0.0.1
客户端的端口:3928
客户端的信息:我是徐越1


参考地址:http://www.2cto.com/kf/201209/158518.html

本文转自IT徐胖子的专栏博客51CTO博客,原文链接http://blog.51cto.com/woshixy/1098701如需转载请自行联系原作者


woshixuye111