溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中如何進(jìn)行TCP和套接字入門

發(fā)布時(shí)間:2021-10-29 10:01:48 來(lái)源:億速云 閱讀:205 作者:柒染 欄目:編程語(yǔ)言

今天就跟大家聊聊有關(guān)Java中如何進(jìn)行TCP和套接字入門,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

JDK 提供了對(duì) TCP(Transmission Control Protocol,傳輸控制協(xié)議)和 UDP(User Datagram Protocol,用戶數(shù)據(jù)報(bào)協(xié)議)這兩個(gè)數(shù)據(jù)傳輸協(xié)議的支持。本文開(kāi)始探討 TCP。

TCP 基礎(chǔ)知識(shí)

在“服務(wù)器-客戶端”這種架構(gòu)中,服務(wù)器和客戶端各自維護(hù)一個(gè)端點(diǎn),兩個(gè)端點(diǎn)需要通過(guò)網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)交換。TCP 為這種需求提供了一種可靠的流式連接,流式的意思是傳出和收到的數(shù)據(jù)都是連續(xù)的字節(jié),沒(méi)有對(duì)數(shù)據(jù)量進(jìn)行大小限制。一個(gè)端點(diǎn)由 IP 地址和端口構(gòu)成(專業(yè)術(shù)語(yǔ)為“元組 {IP 地址, 端口}”)。這樣,一個(gè)連接就可以由元組 {本地地址, 本地端口, 遠(yuǎn)程地址, 遠(yuǎn)程端口} 來(lái)表示。

連接過(guò)程

在 TCP 編程接口中,端點(diǎn)體現(xiàn)為 TCP 套接字。共有兩種 TCP 套接字:主動(dòng)和被動(dòng),“被動(dòng)”狀態(tài)也常被稱為“偵聽(tīng)”狀態(tài)。服務(wù)器和客戶端利用套接字進(jìn)行連接的過(guò)程如下:

1、服務(wù)器創(chuàng)建一個(gè)被動(dòng)套接字,開(kāi)始循環(huán)偵聽(tīng)客戶端的連接。

2、客戶端創(chuàng)建一個(gè)主動(dòng)套接字,連接服務(wù)器。

3、服務(wù)器接受客戶端的連接,并創(chuàng)建一個(gè)代表該連接的主動(dòng)套接字。

4、服務(wù)器和客戶端通過(guò)步驟 2 和 3 中創(chuàng)建的兩個(gè)主動(dòng)套接字進(jìn)行數(shù)據(jù)傳輸。

下面是連接過(guò)程的圖解:

Java中如何進(jìn)行TCP和套接字入門

一個(gè)簡(jiǎn)單的 TCP 服務(wù)器

JDK 提供了 ServerSocket 類來(lái)代表 TCP 服務(wù)器的被動(dòng)套接字。下面的代碼演示了一個(gè)簡(jiǎn)單的 TCP 服務(wù)器(多線程阻塞模式),它不斷偵聽(tīng)并接受客戶端的連接,然后將客戶端發(fā)送過(guò)來(lái)的文本按行讀取,全文轉(zhuǎn)換為大寫后返回給客戶端,直到客戶端發(fā)送文本行 bye:

public class TcpServer implements Runnable {       private ServerSocket serverSocket;           public TcpServer(int port) throws IOException {           // 創(chuàng)建綁定到某個(gè)端口的 TCP 服務(wù)器被動(dòng)套接字。           serverSocket = new ServerSocket(port);       }           @Override     public void run() {           while (true) {               try {                   // 以阻塞的方式接受一個(gè)客戶端連接,返回代表該連接的主動(dòng)套接字。                   Socket socket = serverSocket.accept();                   // 在新線程中處理客戶端連接。                   new Thread(new ClientHandler(socket)).start();               } catch (IOException ex) {                   ex.printStackTrace();               }           }       }   }       public class ClientHandler implements Runnable {       private Socket socket;           public ClientHandler(Socket socket) {           this.socket = Objects.requireNonNull(socket);       }           @Override     public void run() {           try (Socket s = socket) {  // 減少代碼量的花招……               // 包裝套接字的輸入流以讀取客戶端發(fā)送的文本行。               BufferedReader in = new BufferedReader(new InputStreamReader(                       s.getInputStream(), StandardCharsets.UTF_8));               // 包裝套接字的輸出流以向客戶端發(fā)送轉(zhuǎn)換結(jié)果。               PrintWriter out = new PrintWriter(new OutputStreamWriter(                       s.getOutputStream(), StandardCharsets.UTF_8), true);                   String line = null;               while ((line = in.readLine()) != null) {                   if (line.equals("bye")) {                       break;                   }                       // 將轉(zhuǎn)換結(jié)果輸出給客戶端。                   out.println(line.toUpperCase(Locale.ENGLISH));               }           } catch (IOException ex) {               ex.printStackTrace();           }       }   }

阻塞模式的編程方式簡(jiǎn)單,但存在性能問(wèn)題,因?yàn)榉?wù)器線程會(huì)卡死在接受客戶端的 accept() 方法上,不能有效利用資源。套接字支持非阻塞模式,現(xiàn)在暫時(shí)略過(guò)。

一個(gè)簡(jiǎn)單的 TCP 客戶端

JDK 提供了 Socket 類來(lái)代表 TCP 客戶端的主動(dòng)套接字。下面的代碼演示了上述服務(wù)器的客戶端:

public class TcpClient implements Runnable {       private Socket socket;           public TcpClient(String host, int port) throws IOException {           // 創(chuàng)建連接到服務(wù)器的套接字。           socket = new Socket(host, port);       }           @Override     public void run() {           try (Socket s = socket) {  // 再次減少代碼量……               // 包裝套接字的輸出流以向服務(wù)器發(fā)送文本行。               PrintWriter out = new PrintWriter(new OutputStreamWriter(                       s.getOutputStream(), StandardCharsets.UTF_8), true);               // 包裝套接字的輸入流以讀取服務(wù)器返回的文本行。               BufferedReader in = new BufferedReader(new InputStreamReader(                       s.getInputStream(), StandardCharsets.UTF_8));                   Console console = System.console();               String line = null;               while ((line = console.readLine()) != null) {                   if (line.equals("bye")) {                       break;                   }                       // 將文本行發(fā)送給服務(wù)器。                   out.println(line);                   // 打印服務(wù)器返回的文本行。                   console.writer().println(in.readLine());               }                   // 通知服務(wù)器關(guān)閉連接。               out.println("bye");           } catch (IOException ex) {               ex.printStackTrace();           }       }   }

從 JDK 文檔可以看到,ServerSocket 和 Socket 在初始化的時(shí)候,可以設(shè)定一些參數(shù),還支持延遲綁定。這些東西對(duì)性能和行為都有所影響。后續(xù)兩篇文章將分別詳解這兩個(gè)類的初始化。

看完上述內(nèi)容,你們對(duì)Java中如何進(jìn)行TCP和套接字入門有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI