<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Java 套接字教程 原文:http://zetcode.com/java/socket/ Java 套接字教程展示了如何使用套接字在 Java 中進行網絡編程。 套接字編程是低級的。 本教程的目的是介紹包括這些低級詳細信息的網絡編程。 有些高級 API 可能更適合實際任務。 例如,Java 11 引入了`HttpClient`,而 Spring 具有`Webclient`。 ## Java 套接字 在編程中,套接字是網絡上運行的兩個程序之間的通信端點。 套接字類用于在客戶端程序和服務器程序之間創建連接。 `Socket`代表客戶端套接字,`ServerSocket`代表服務器套接字。 > **注意**:在網絡中,“套接字”一詞具有不同的含義。 它用于 IP 地址和端口號的組合。 `ServerSocket`綁定到端口號,這是通過客戶端和服務器同意進行通信的唯一 ID。 `Socket`和`ServerSocket`用于 TCP 協議。 `DatagramSocket`和`DatagramPacket`用于 UDP 協議。 TCP 更可靠,具有大量錯誤檢查并需要更多資源。 HTTP,SMTP 或 FTP 等服務使用它。 UDP 的可靠性要差得多,錯誤檢查的能力也有限,所需資源也更少。 VoIP 等服務使用它。 `DatagramSocket`是用于發送和接收數據報包的套接字。 數據報包由`DatagramPacket`類表示。 在數據報套接字上發送或接收的每個數據包都經過單獨尋址和路由。 從一臺機器發送到另一臺機器的多個數據包可能會以不同的方式路由,并且可能以任何順序到達。 ## Java 套接字時間客戶端 是提供當前時間的服務器。 客戶端無需任何命令即可直接連接到服務器,服務器以當前時間作為響應。 > **注意**:時間服務器來來往往,因此我們可能需要在 <https://www.ntppool.org/en/> 上找到可用的服務器。 在我們的示例中,我們選擇了瑞典的服務器。 `com/zetcode/SocketTimeClient.java` ```java package com.zetcode; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; // time servers come and go; we might need to // find a functioning server on https://www.ntppool.org/en/ public class SocketTimeClient { public static void main(String[] args) throws IOException { var hostname = "3.se.pool.ntp.org"; int port = 13; try (var socket = new Socket(hostname, port)) { try (var reader = new InputStreamReader(socket.getInputStream())) { int character; var output = new StringBuilder(); while ((character = reader.read()) != -1) { output.append((char) character); } System.out.println(output); } } } } ``` 該示例連接到時間服務器并接收當前時間。 ```java var hostname = "3.se.pool.ntp.org"; int port = 13; ``` 這是瑞典的時間服務器; 13 端口是白天服務的標準端口。 ```java try (var socket = new Socket(hostname, port)) { ``` 流客戶端套接字已創建。 它連接到命名主機上的指定端口號。 使用 Java 的`try-with-resources`語句自動關閉套接字。 ```java try (var reader = new InputStreamReader(socket.getInputStream())) { ``` `getInputStream()`返回此套接字的輸入流。 我們從此輸入流中讀取服務器的響應。 套接字之間的通信以字節為單位; 因此,我們將`InputStreamReader`用作字節和字符之間的橋梁。 ```java int character; var output = new StringBuilder(); while ((character = reader.read()) != -1) { output.append((char) character); } System.out.println(output); ``` 由于響應消息很小,因此我們可以逐個字符地讀取它,而對性能的影響很小。 ## Java 套接字 Whois 客戶端 Whois 是基于 TCP 的面向事務的查詢/響應協議,被廣泛用于向互聯網用戶提供信息服務。 它用于查詢域名或 IP 地址塊所有者等信息。 > **注意**:大多數 Whois 服務器僅提供有限的信息(例如,僅針對選定的域名),并且有關域名所有者的信息通常由域名注冊機構匿名。 Whois 協議使用端口 43。 `com/zetcode/WhoisClientEx.java` ```java package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; // probing whois.iana.org might give the right // whois server public class WhoisClientEx { public static void main(String[] args) throws IOException { var domainName = "example.com"; var whoisServer = "whois.nic.me"; int port = 43; try (var socket = new Socket(whoisServer, port)) { try (var writer = new PrintWriter(socket.getOutputStream(), true)) { writer.println(domainName); try (var reader = new BufferedReader( new InputStreamReader(socket.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } } } } } ``` 在該示例中,我們探查了有關域名所有者的信息。 ```java try (var writer = new PrintWriter(socket.getOutputStream(), true)) { writer.println(domainName); ... ``` 我們獲得套接字的輸出流,并將其包裝到`PrintWriter`中。 `PrintWriter`會將我們的字符轉換為字節。 使用`println()`,將域名寫入流中。 通過套接字的通信被緩沖。 `PrintWriter`的第二個參數是`autoFlush`; 如果設置為`true`,則在每個`println()`之后將刷新緩沖區。 ```java try (var reader = new BufferedReader( new InputStreamReader(socket.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } ``` 來自服務器的響應被讀取并寫入控制臺。 ## Java 套接字 GET 請求 在下面的示例中,我們創建一個 GET 請求。 HTTP GET 請求用于檢索特定資源。 `com/zetcode/JavaSocketGetRequest.java` ```java package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class SocketGetRequest { public static void main(String[] args) throws IOException { try (var socket = new Socket("webcode.me", 80)) { try (var wtr = new PrintWriter(socket.getOutputStream())) { // create GET request wtr.print("GET / HTTP/1.1\r\n"); wtr.print("Host: www.webcode.me\r\n"); wtr.print("\r\n"); wtr.flush(); socket.shutdownOutput(); String outStr; try (var bufRead = new BufferedReader(new InputStreamReader( socket.getInputStream()))) { while ((outStr = bufRead.readLine()) != null) { System.out.println(outStr); } socket.shutdownInput(); } } } } } ``` 該示例從網站檢索 HTML 頁面。 ```java try (var socket = new Socket("webcode.me", 80)) { ``` 我們在端口 80 上的指定網頁上打開一個套接字。HTTP 協議使用端口 80。 ```java try (var wtr = new PrintWriter(socket.getOutputStream())) { ``` 我們將在協議上發布文本命令; 因此,我們為套接字輸出流創建一個`PrintWriter`。 由于我們沒有將`autoFlush`選項設置為`true`,因此我們需要手動刷新緩沖區。 ```java // create GET request wtr.print("GET / HTTP/1.1\r\n"); wtr.print("Host: www.webcode.me\r\n"); wtr.print("\r\n"); wtr.flush(); ``` 我們創建一個 HTTP GET 請求,該請求檢索指定網頁的主頁。 請注意,文本命令以`\r\n`(CRLF)字符完成。 這些是必需的通信詳細信息,在 RFC 2616 文檔中進行了描述。 ```java socket.shutdownOutput(); ``` `shutdownOutput`禁用此套接字的輸出流。 最后必須關閉連接。 ```java try (var bufRead = new BufferedReader(new InputStreamReader( socket.getInputStream()))) { ``` 對于服務器響應,我們打開一個套接字輸入流,并使用`InputStreamReader`將字節轉換為字符。 我們還緩沖讀取操作。 ```java while ((outStr = bufRead.readLine()) != null) { System.out.println(outStr); } ``` 我們逐行讀取數據。 ```java socket.shutdownInput(); ``` 最后,我們也關閉了輸入流。 ## Java 套接字 HEAD 請求 在下一個示例中,我們使用 Java 套接字創建 HEAD 請求。 HEAD 方法與 GET 方法相同,不同之處在于服務器在響應中不返回消息正文。 它僅返回標頭。 `com/zetcode/SocketHeadRequest.java` ```java package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class SocketHeadRequest { public static void main(String[] args) throws IOException { var hostname = "webcode.me"; int port = 80; try (var socket = new Socket(hostname, port)) { try (var writer = new PrintWriter(socket.getOutputStream(), true)) { writer.println("HEAD / HTTP/1.1"); writer.println("Host: " + hostname); writer.println("User-Agent: Console Http Client"); writer.println("Accept: text/html"); writer.println("Accept-Language: en-US"); writer.println("Connection: close"); writer.println(); try (var reader = new BufferedReader(new InputStreamReader( socket.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } } } } } ``` 該示例檢索指定網頁的標題。 ```java writer.println("HEAD / HTTP/1.1"); ``` 我們發出 HEAD 命令。 ```java writer.println("Connection: close"); ``` 在 HTTP 協議版本 1.1 中,除非另有聲明,否則所有連接均被視為持久連接(保持活動狀態)。 通過將選項設置為`false`,我們通知我們要在請求/響應周期之后完成連接。 ## Java `ServerSocket`日期服務器 下面的示例使用`ServerSocket`創建一個非常簡單的服務器。 `ServerSocket`創建綁定到指定端口的服務器套接字。 `com/zetcode/DateServer.java` ```java package com.zetcode; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.time.LocalDate; public class DateServer { public static void main(String[] args) throws IOException { int port = 8081; try (var listener = new ServerSocket(port)) { System.out.printf("The started on port %d%n", port); while (true) { try (var socket = listener.accept()) { try (var pw = new PrintWriter(socket.getOutputStream(), true)) { pw.println(LocalDate.now()); } } } } } } ``` 該示例創建一個返回當前日期的服務器。 最后必須手動終止該程序。 ```java int port = 8081; try (var listener = new ServerSocket(port)) { ``` 在端口 8081 上創建一個服務器套接字。 ```java try (var socket = listener.accept()) { ``` `accept()`方法監聽與此套接字建立的連接并接受它。 該方法將阻塞,直到建立連接為止。 ```java try (var pw = new PrintWriter(socket.getOutputStream(), true)) { pw.println(LocalDate.now()); } ``` 我們將當前日期寫入套接字輸出流。 `get_request.py` ```java #!/usr/bin/env python3 import socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect(("localhost" , 8081)) s.sendall(b"GET / HTTP/1.1\r\nHost: localhost\r\nAccept: text/html\r\n\r\n") print(str(s.recv(4096), 'utf-8')) ``` 我們有一個 Python 腳本向服務器發出 GET 請求。 ```java $ get_request.py 2019-07-15 ``` 這是輸出。 ## Java 套接字客戶端/服務器示例 在下面的示例中,我們有一個服務器和一個客戶端。 服務器反轉從客戶端發送的文本。 這個例子很簡單而且很阻塞。 為了改善它,我們需要包括線程。 `com/zetcode/ReverseServer.java` ```java package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; // This server communicates only with one client at a time. // It must disconnect from a client first to communicate // with another client. It receives a bye command from a client // to close a connection. public class ReverseServer { public static void main(String[] args) throws IOException { int port = 8081; try (var serverSocket = new ServerSocket(port)) { System.out.println("Server is listening on port " + port); while (true) { try (var socket = serverSocket.accept()) { System.out.println("client connected"); try (var reader = new BufferedReader(new InputStreamReader( socket.getInputStream())); var writer = new PrintWriter(socket.getOutputStream(), true)) { String text; do { text = reader.readLine(); if (text != null) { var reversed = new StringBuilder(text).reverse().toString(); writer.println("Server: " + reversed); System.out.println(text); } } while (!"bye".equals(text)); System.out.println("client disconnected"); } } } } } } ``` `ReverseServer`將反向字符串發送回客戶端。 一次僅與一個客戶端通信。 它必須首先與客戶端斷開連接才能與另一個客戶端通信。 它從客戶端收到一個`bye`命令以關閉連接。 ```java try (var reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); var writer = new PrintWriter(socket.getOutputStream(), true)) { ``` 我們有一個套接字輸入流,用于讀取客戶端數據,以及套接字輸出流,用于將響應發送回客戶端; 輸出流和連接已關閉。 ```java do { text = reader.readLine(); if (text != null) { var reversed = new StringBuilder(text).reverse().toString(); writer.println("Server: " + reversed); System.out.println(text); } } while (!"bye".equals(text)); ``` 為單個客戶端創建了一個`do-while`循環。 我們從客戶端讀取數據,然后將修改后的內容發送回去。 收到客戶端的再見命令后,循環結束。 在此之前,沒有其他客戶端可以連接到服務器。 `com/zetcode/ReverseClient.java` ```java package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; // the client must send a bye command to // inform the server to close the connection public class ReverseClient { public static void main(String[] args) throws IOException { var hostname = "localhost"; int port = 8081; try (var socket = new Socket(hostname, port)) { try (var writer = new PrintWriter(socket.getOutputStream(), true)) { try (var scanner = new Scanner(System.in)) { try (var reader = new BufferedReader(new InputStreamReader( socket.getInputStream()))) { String command; do { System.out.print("Enter command: "); command = scanner.nextLine(); writer.println(command); var data = reader.readLine(); System.out.println(data); } while (!command.equals("bye")); } } } } } } ``` 客戶端將文本數據發送到服務器。 ```java do { System.out.print("Enter command: "); command = scanner.nextLine(); writer.println(command); var data = reader.readLine(); System.out.println(data); } while (!command.equals("bye")); ``` 我們從控制臺讀取輸入,并將其發送到服務器。 當我們發送`bye`命令時,`while`循環完成,該命令通知服務器可以關閉連接。 ## Java `DatagramSocket`示例 UDP 是一種通信協議,它通過網絡傳輸獨立的數據包,不保證到達且也不保證傳遞順序。 使用 UDP 的一項服務是每日報價(QOTD)。 下面的示例創建一個連接到 QOTD 服務的客戶端程序。 `com/zetcode/DatagramSocketEx.java` ```java package com.zetcode; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; // DatagramSocket provides network communication via UDP protocol // The Quote of the Day (QOTD) service is a member of the Internet protocol // suite, defined in RFC 865 public class DatagramSocketEx { public static void main(String[] args) throws IOException { var hostname = "djxmmx.net"; int port = 17; var address = InetAddress.getByName(hostname); try (var socket = new DatagramSocket()) { var request = new DatagramPacket(new byte[1], 1, address, port); socket.send(request); var buffer = new byte[512]; var response = new DatagramPacket(buffer, buffer.length); socket.receive(response); var quote = new String(buffer, 0, response.getLength()); System.out.println(quote); } } } ``` 該示例從報價服務檢索報價并將其打印到終端。 ```java var address = InetAddress.getByName(hostname); ``` 我們從主機名獲得 IP 地址。 ```java try (var socket = new DatagramSocket()) { ``` 創建了`DatagramSocket`。 ```java var request = new DatagramPacket(new byte[1], 1, address, port); ``` 創建了`DatagramPacket`。 由于 QOTD 服務不需要來自客戶端的數據,因此我們發送了一個空的小型數組。 每次發送數據包時,我們都需要指定數據,地址和端口。 ```java socket.send(request); ``` 數據包通過`send()`發送到其目的地。 ```java var buffer = new byte[512]; var response = new DatagramPacket(buffer, buffer.length); socket.receive(response); ``` 我們收到來自服務的數據包。 ```java var quote = new String(buffer, 0, response.getLength()); System.out.println(quote); ``` 我們將接收到的字節轉換為字符串并打印。 在本教程中,我們創建了帶有套接字的網絡 Java 程序。 您可能也對相關教程感興趣: [Java HTTP GET/POST 請求教程](/java/getpostrequest/), [Java `InputStreamReader`教程](/java/inputstreamreader/), [Java Servlet 教程](/java/servlet/)和 [Java 教程](/lang/java/) 。 列出[所有 Java 教程](/all/#java)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看