'Java Socket:飛鴿傳書的網絡套接字'

Java 掃描儀 Windows 電腦 Line 通信 操作系統 Java架構師CAT 2019-08-29
"

在古代,由於通信不便利,一些聰明的人就利用鴿子會飛且飛得比較快、會辨認方向的優點,對其進行了馴化,用來進行消息的傳遞——也就是所謂的“飛鴿傳書”。而在 Java 中,網絡套接字(Socket)扮演了同樣的角色。

套接字(Socket)是一個抽象層,應用程序可以通過它發送或接收數據;就像操作文件那樣可以打開、讀寫和關閉。套接字允許應用程序將 I/O 應用於網絡中,並與其他應用程序進行通信。網絡套接字是 IP 地址與端口的組合。

01、ping 與 telnet

“老王啊,能不能幫我看一下這個問題呢,明明本地可以進行網絡通信,可等我部署到服務器上時就通信不了了,搞了半天也不知道什麼原因,我看代碼是沒有問題的。”小二的語氣中充滿了沮喪。

“ping 過嗎?或者 telnet 了嗎?”老王頭都沒回,冷冰冰地扔出去了這句話。

哦,我去試試。”小二心頭掠過一絲愧疚。

ping 與 telnet 這兩個命令,對調試網絡程序有著非常大的幫助。

ping,一種計算機網絡工具,用來測試數據包能否透過 IP 協議到達特定主機。ping 會向目標主機發出一個 ICMP 的請求回顯數據包,並等待接收回顯響應數據包。

例如,我們 ping 一下博客園。截圖如下。

"

在古代,由於通信不便利,一些聰明的人就利用鴿子會飛且飛得比較快、會辨認方向的優點,對其進行了馴化,用來進行消息的傳遞——也就是所謂的“飛鴿傳書”。而在 Java 中,網絡套接字(Socket)扮演了同樣的角色。

套接字(Socket)是一個抽象層,應用程序可以通過它發送或接收數據;就像操作文件那樣可以打開、讀寫和關閉。套接字允許應用程序將 I/O 應用於網絡中,並與其他應用程序進行通信。網絡套接字是 IP 地址與端口的組合。

01、ping 與 telnet

“老王啊,能不能幫我看一下這個問題呢,明明本地可以進行網絡通信,可等我部署到服務器上時就通信不了了,搞了半天也不知道什麼原因,我看代碼是沒有問題的。”小二的語氣中充滿了沮喪。

“ping 過嗎?或者 telnet 了嗎?”老王頭都沒回,冷冰冰地扔出去了這句話。

哦,我去試試。”小二心頭掠過一絲愧疚。

ping 與 telnet 這兩個命令,對調試網絡程序有著非常大的幫助。

ping,一種計算機網絡工具,用來測試數據包能否透過 IP 協議到達特定主機。ping 會向目標主機發出一個 ICMP 的請求回顯數據包,並等待接收回顯響應數據包。

例如,我們 ping 一下博客園。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

telnet,Internet 遠程登錄服務的標準協議和主要方式,可以讓我們坐在家裡的計算機面前,登錄到另一臺遠在天涯海角的遠程計算機上。

"

在古代,由於通信不便利,一些聰明的人就利用鴿子會飛且飛得比較快、會辨認方向的優點,對其進行了馴化,用來進行消息的傳遞——也就是所謂的“飛鴿傳書”。而在 Java 中,網絡套接字(Socket)扮演了同樣的角色。

套接字(Socket)是一個抽象層,應用程序可以通過它發送或接收數據;就像操作文件那樣可以打開、讀寫和關閉。套接字允許應用程序將 I/O 應用於網絡中,並與其他應用程序進行通信。網絡套接字是 IP 地址與端口的組合。

01、ping 與 telnet

“老王啊,能不能幫我看一下這個問題呢,明明本地可以進行網絡通信,可等我部署到服務器上時就通信不了了,搞了半天也不知道什麼原因,我看代碼是沒有問題的。”小二的語氣中充滿了沮喪。

“ping 過嗎?或者 telnet 了嗎?”老王頭都沒回,冷冰冰地扔出去了這句話。

哦,我去試試。”小二心頭掠過一絲愧疚。

ping 與 telnet 這兩個命令,對調試網絡程序有著非常大的幫助。

ping,一種計算機網絡工具,用來測試數據包能否透過 IP 協議到達特定主機。ping 會向目標主機發出一個 ICMP 的請求回顯數據包,並等待接收回顯響應數據包。

例如,我們 ping 一下博客園。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

telnet,Internet 遠程登錄服務的標準協議和主要方式,可以讓我們坐在家裡的計算機面前,登錄到另一臺遠在天涯海角的遠程計算機上。

Java Socket:飛鴿傳書的網絡套接字

在 Windows 系統中,telnet 一般是默認安裝的,但未激活(可以在控制面板中激活它)。

例如,我們 telnet 一下火(shui)土(mu)社區。截圖如下。

"

在古代,由於通信不便利,一些聰明的人就利用鴿子會飛且飛得比較快、會辨認方向的優點,對其進行了馴化,用來進行消息的傳遞——也就是所謂的“飛鴿傳書”。而在 Java 中,網絡套接字(Socket)扮演了同樣的角色。

套接字(Socket)是一個抽象層,應用程序可以通過它發送或接收數據;就像操作文件那樣可以打開、讀寫和關閉。套接字允許應用程序將 I/O 應用於網絡中,並與其他應用程序進行通信。網絡套接字是 IP 地址與端口的組合。

01、ping 與 telnet

“老王啊,能不能幫我看一下這個問題呢,明明本地可以進行網絡通信,可等我部署到服務器上時就通信不了了,搞了半天也不知道什麼原因,我看代碼是沒有問題的。”小二的語氣中充滿了沮喪。

“ping 過嗎?或者 telnet 了嗎?”老王頭都沒回,冷冰冰地扔出去了這句話。

哦,我去試試。”小二心頭掠過一絲愧疚。

ping 與 telnet 這兩個命令,對調試網絡程序有著非常大的幫助。

ping,一種計算機網絡工具,用來測試數據包能否透過 IP 協議到達特定主機。ping 會向目標主機發出一個 ICMP 的請求回顯數據包,並等待接收回顯響應數據包。

例如,我們 ping 一下博客園。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

telnet,Internet 遠程登錄服務的標準協議和主要方式,可以讓我們坐在家裡的計算機面前,登錄到另一臺遠在天涯海角的遠程計算機上。

Java Socket:飛鴿傳書的網絡套接字

在 Windows 系統中,telnet 一般是默認安裝的,但未激活(可以在控制面板中激活它)。

例如,我們 telnet 一下火(shui)土(mu)社區。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

使用 telnet 登錄遠程計算機時,需要遠程計算機上運行一個服務,它一直不停地等待那些希望和它進行連接的網絡請求;當接收到一個客戶端的網絡連接時,它便喚醒正在監聽網絡連接請求的服務器進程,併為兩者建立連接。連接會一直保持,直到某一方中止。

不過,需要注意的是,telnet 在格外重視安全的現代網絡技術中並不受到重用。因為 telnet 是一個明文傳輸協議,用戶的所有內容(包括用戶名和密碼)都沒有經過加密,安全隱患非常大。

02、Socket 實例

不知道你有沒有體驗一下 telnet 火土社區的那條命令,結果非常有趣。我們也可以通過 Java 的客戶端套接字(Socket)實現,代碼示例如下。

try (Socket socket = new Socket("bbs.newsmth.net", 23);) {
InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(is, "gbk");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

1)建立套接字連接非常簡單,只需要一行代碼:

Socket socket = new Socket(host, port)


host 為主機名,port 為端口號(23 為默認的 telnet 端口號)。如果無法確定主機的 IP 地址,則拋出 UnknownHostException 異常;如果在創建套接字時發生 IO 錯誤,則拋出 IOException 異常。

需要注意的是,套接字在建立的時候,如果遠程主機不可訪問,這段代碼就會阻塞很長時間,直到底層操作系統的限制而拋出異常。所以一般會在套接字建立後設置一個超時時間。

Socket socket = new Socket(...);
socket.setSoTimeout(10000); // 單位為毫秒

2)套接字連接成功後,可以通過 java.net.Socket 類的 getInputStream() 方法獲取輸入流。有了 InputStream 對象後,可以藉助文本掃描器類(Scanner)將其中的內容打印出來。

InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(is, "gbk");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}

部分結果(完整結果自己親手實踐一下哦)如下圖所示:

"

在古代,由於通信不便利,一些聰明的人就利用鴿子會飛且飛得比較快、會辨認方向的優點,對其進行了馴化,用來進行消息的傳遞——也就是所謂的“飛鴿傳書”。而在 Java 中,網絡套接字(Socket)扮演了同樣的角色。

套接字(Socket)是一個抽象層,應用程序可以通過它發送或接收數據;就像操作文件那樣可以打開、讀寫和關閉。套接字允許應用程序將 I/O 應用於網絡中,並與其他應用程序進行通信。網絡套接字是 IP 地址與端口的組合。

01、ping 與 telnet

“老王啊,能不能幫我看一下這個問題呢,明明本地可以進行網絡通信,可等我部署到服務器上時就通信不了了,搞了半天也不知道什麼原因,我看代碼是沒有問題的。”小二的語氣中充滿了沮喪。

“ping 過嗎?或者 telnet 了嗎?”老王頭都沒回,冷冰冰地扔出去了這句話。

哦,我去試試。”小二心頭掠過一絲愧疚。

ping 與 telnet 這兩個命令,對調試網絡程序有著非常大的幫助。

ping,一種計算機網絡工具,用來測試數據包能否透過 IP 協議到達特定主機。ping 會向目標主機發出一個 ICMP 的請求回顯數據包,並等待接收回顯響應數據包。

例如,我們 ping 一下博客園。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

telnet,Internet 遠程登錄服務的標準協議和主要方式,可以讓我們坐在家裡的計算機面前,登錄到另一臺遠在天涯海角的遠程計算機上。

Java Socket:飛鴿傳書的網絡套接字

在 Windows 系統中,telnet 一般是默認安裝的,但未激活(可以在控制面板中激活它)。

例如,我們 telnet 一下火(shui)土(mu)社區。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

使用 telnet 登錄遠程計算機時,需要遠程計算機上運行一個服務,它一直不停地等待那些希望和它進行連接的網絡請求;當接收到一個客戶端的網絡連接時,它便喚醒正在監聽網絡連接請求的服務器進程,併為兩者建立連接。連接會一直保持,直到某一方中止。

不過,需要注意的是,telnet 在格外重視安全的現代網絡技術中並不受到重用。因為 telnet 是一個明文傳輸協議,用戶的所有內容(包括用戶名和密碼)都沒有經過加密,安全隱患非常大。

02、Socket 實例

不知道你有沒有體驗一下 telnet 火土社區的那條命令,結果非常有趣。我們也可以通過 Java 的客戶端套接字(Socket)實現,代碼示例如下。

try (Socket socket = new Socket("bbs.newsmth.net", 23);) {
InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(is, "gbk");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

1)建立套接字連接非常簡單,只需要一行代碼:

Socket socket = new Socket(host, port)


host 為主機名,port 為端口號(23 為默認的 telnet 端口號)。如果無法確定主機的 IP 地址,則拋出 UnknownHostException 異常;如果在創建套接字時發生 IO 錯誤,則拋出 IOException 異常。

需要注意的是,套接字在建立的時候,如果遠程主機不可訪問,這段代碼就會阻塞很長時間,直到底層操作系統的限制而拋出異常。所以一般會在套接字建立後設置一個超時時間。

Socket socket = new Socket(...);
socket.setSoTimeout(10000); // 單位為毫秒

2)套接字連接成功後,可以通過 java.net.Socket 類的 getInputStream() 方法獲取輸入流。有了 InputStream 對象後,可以藉助文本掃描器類(Scanner)將其中的內容打印出來。

InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(is, "gbk");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}

部分結果(完整結果自己親手實踐一下哦)如下圖所示:

Java Socket:飛鴿傳書的網絡套接字

03、ServerSocket 實例

接下來,我們模擬一個遠程服務,通過 java.net.ServerSocket 實現。代碼示例如下。

try (ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
Scanner scanner = new Scanner(is)) {
PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "gbk"), true);
pw.println("你好啊,歡迎關注「沉默王二」 公眾號,回覆關鍵字「2048」 領取程序員進階必讀資料包");
boolean done = false;
while (!done && scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
if ("2048".equals(line)) {
done = true;
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

1)建立服務器端的套接字也比較簡單,只需要指定一個能夠獨佔的端口號就可以了(0~1023 這些端口都已經被系統預留了)。

ServerSocket server = new ServerSocket(8888);


2)調用 ServerSocket 對象的 accept() 等待客戶端套接字的連接請求。一旦監聽到客戶端的套接字請求,就會返回一個表示連接已建立的 Socket 對象,可以從中獲取到輸入流和輸出流。

Socket socket = server.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();

客戶端套接字發送的所有信息都會包裹在服務器端套接字的輸入流中;而服務器端套接字發送的所有信息都會包裹在客戶端套接字的輸出流中。

3)服務器端可以通過以下代碼向客戶端發送消息。

PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "gbk"), true);
pw.println("你好啊,歡迎關注「沉默王二」 公眾號,回覆關鍵字「2048」 領取程序員進階必讀資料包");

4)服務器端可以通過以下代碼讀取客戶端發送過來的消息。

Scanner scanner = new Scanner(is);
boolean done = false;
while (!done && scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
if ("2048".equals(line)) {
done = true;
}
}

運行該服務後,可以通過 telnet localhost 8888 命令連接該遠程服務,不出所料,你將會看到以下信息。

"

在古代,由於通信不便利,一些聰明的人就利用鴿子會飛且飛得比較快、會辨認方向的優點,對其進行了馴化,用來進行消息的傳遞——也就是所謂的“飛鴿傳書”。而在 Java 中,網絡套接字(Socket)扮演了同樣的角色。

套接字(Socket)是一個抽象層,應用程序可以通過它發送或接收數據;就像操作文件那樣可以打開、讀寫和關閉。套接字允許應用程序將 I/O 應用於網絡中,並與其他應用程序進行通信。網絡套接字是 IP 地址與端口的組合。

01、ping 與 telnet

“老王啊,能不能幫我看一下這個問題呢,明明本地可以進行網絡通信,可等我部署到服務器上時就通信不了了,搞了半天也不知道什麼原因,我看代碼是沒有問題的。”小二的語氣中充滿了沮喪。

“ping 過嗎?或者 telnet 了嗎?”老王頭都沒回,冷冰冰地扔出去了這句話。

哦,我去試試。”小二心頭掠過一絲愧疚。

ping 與 telnet 這兩個命令,對調試網絡程序有著非常大的幫助。

ping,一種計算機網絡工具,用來測試數據包能否透過 IP 協議到達特定主機。ping 會向目標主機發出一個 ICMP 的請求回顯數據包,並等待接收回顯響應數據包。

例如,我們 ping 一下博客園。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

telnet,Internet 遠程登錄服務的標準協議和主要方式,可以讓我們坐在家裡的計算機面前,登錄到另一臺遠在天涯海角的遠程計算機上。

Java Socket:飛鴿傳書的網絡套接字

在 Windows 系統中,telnet 一般是默認安裝的,但未激活(可以在控制面板中激活它)。

例如,我們 telnet 一下火(shui)土(mu)社區。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

使用 telnet 登錄遠程計算機時,需要遠程計算機上運行一個服務,它一直不停地等待那些希望和它進行連接的網絡請求;當接收到一個客戶端的網絡連接時,它便喚醒正在監聽網絡連接請求的服務器進程,併為兩者建立連接。連接會一直保持,直到某一方中止。

不過,需要注意的是,telnet 在格外重視安全的現代網絡技術中並不受到重用。因為 telnet 是一個明文傳輸協議,用戶的所有內容(包括用戶名和密碼)都沒有經過加密,安全隱患非常大。

02、Socket 實例

不知道你有沒有體驗一下 telnet 火土社區的那條命令,結果非常有趣。我們也可以通過 Java 的客戶端套接字(Socket)實現,代碼示例如下。

try (Socket socket = new Socket("bbs.newsmth.net", 23);) {
InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(is, "gbk");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

1)建立套接字連接非常簡單,只需要一行代碼:

Socket socket = new Socket(host, port)


host 為主機名,port 為端口號(23 為默認的 telnet 端口號)。如果無法確定主機的 IP 地址,則拋出 UnknownHostException 異常;如果在創建套接字時發生 IO 錯誤,則拋出 IOException 異常。

需要注意的是,套接字在建立的時候,如果遠程主機不可訪問,這段代碼就會阻塞很長時間,直到底層操作系統的限制而拋出異常。所以一般會在套接字建立後設置一個超時時間。

Socket socket = new Socket(...);
socket.setSoTimeout(10000); // 單位為毫秒

2)套接字連接成功後,可以通過 java.net.Socket 類的 getInputStream() 方法獲取輸入流。有了 InputStream 對象後,可以藉助文本掃描器類(Scanner)將其中的內容打印出來。

InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(is, "gbk");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}

部分結果(完整結果自己親手實踐一下哦)如下圖所示:

Java Socket:飛鴿傳書的網絡套接字

03、ServerSocket 實例

接下來,我們模擬一個遠程服務,通過 java.net.ServerSocket 實現。代碼示例如下。

try (ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
Scanner scanner = new Scanner(is)) {
PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "gbk"), true);
pw.println("你好啊,歡迎關注「沉默王二」 公眾號,回覆關鍵字「2048」 領取程序員進階必讀資料包");
boolean done = false;
while (!done && scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
if ("2048".equals(line)) {
done = true;
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

1)建立服務器端的套接字也比較簡單,只需要指定一個能夠獨佔的端口號就可以了(0~1023 這些端口都已經被系統預留了)。

ServerSocket server = new ServerSocket(8888);


2)調用 ServerSocket 對象的 accept() 等待客戶端套接字的連接請求。一旦監聽到客戶端的套接字請求,就會返回一個表示連接已建立的 Socket 對象,可以從中獲取到輸入流和輸出流。

Socket socket = server.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();

客戶端套接字發送的所有信息都會包裹在服務器端套接字的輸入流中;而服務器端套接字發送的所有信息都會包裹在客戶端套接字的輸出流中。

3)服務器端可以通過以下代碼向客戶端發送消息。

PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "gbk"), true);
pw.println("你好啊,歡迎關注「沉默王二」 公眾號,回覆關鍵字「2048」 領取程序員進階必讀資料包");

4)服務器端可以通過以下代碼讀取客戶端發送過來的消息。

Scanner scanner = new Scanner(is);
boolean done = false;
while (!done && scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
if ("2048".equals(line)) {
done = true;
}
}

運行該服務後,可以通過 telnet localhost 8888 命令連接該遠程服務,不出所料,你將會看到以下信息。

Java Socket:飛鴿傳書的網絡套接字


PS:可以在當前命令窗口中輸入 2048,服務端收到該消息後會中斷該套接字連接(當前窗口會顯示“遺失對主機的連接”)。

04、為多個客戶端服務

非常遺憾的是,上面的例子中,服務器端只能為一個客戶端服務——這不符合服務器端一對多的要求。

優化方案也非常簡單(你應該也能想得到):服務器端接收到客戶端的套接字請求時,可以啟動一個線程來處理,而主程序繼續等待下一個連接。代碼示例如下。

try (ServerSocket server = new ServerSocket(8888)) {
while (true) {
Socket socket = server.accept();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 套接字處理程序
}
});
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}

線程內部(run(){} 方法裡)用來處理套接字,代碼示例如下:

try {
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
Scanner scanner = new Scanner(is);
// 其他代碼省略
// 向客戶端發送消息
// 讀取客戶端發送過來的消息
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

服務器端代碼優化後重新運行,你就可以通過 telnet 命令測試了。打開一個命令行窗口輸入 telnet localhost 8888,再打開一個新的命令行窗口輸入 telnet localhost 8888,多個窗口都可以和服務器端進行通信,除非服務器端代碼中斷運行。

05、最後

如今大多數基於網絡的軟件,如瀏覽器、即時通訊工具甚至是 P2P 下載都是基於 Socket 實現的,所以掌握 Java Socket 編程還是蠻有必要的。Socket 編程也比較有趣,很多初學者都會編寫一兩個基於“客戶端-服務器端”的小程序來提高自己的編程水平,建議你也試一試。

免費分享Java技術教程,需要的朋友可以在關注後私信我

"

在古代,由於通信不便利,一些聰明的人就利用鴿子會飛且飛得比較快、會辨認方向的優點,對其進行了馴化,用來進行消息的傳遞——也就是所謂的“飛鴿傳書”。而在 Java 中,網絡套接字(Socket)扮演了同樣的角色。

套接字(Socket)是一個抽象層,應用程序可以通過它發送或接收數據;就像操作文件那樣可以打開、讀寫和關閉。套接字允許應用程序將 I/O 應用於網絡中,並與其他應用程序進行通信。網絡套接字是 IP 地址與端口的組合。

01、ping 與 telnet

“老王啊,能不能幫我看一下這個問題呢,明明本地可以進行網絡通信,可等我部署到服務器上時就通信不了了,搞了半天也不知道什麼原因,我看代碼是沒有問題的。”小二的語氣中充滿了沮喪。

“ping 過嗎?或者 telnet 了嗎?”老王頭都沒回,冷冰冰地扔出去了這句話。

哦,我去試試。”小二心頭掠過一絲愧疚。

ping 與 telnet 這兩個命令,對調試網絡程序有著非常大的幫助。

ping,一種計算機網絡工具,用來測試數據包能否透過 IP 協議到達特定主機。ping 會向目標主機發出一個 ICMP 的請求回顯數據包,並等待接收回顯響應數據包。

例如,我們 ping 一下博客園。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

telnet,Internet 遠程登錄服務的標準協議和主要方式,可以讓我們坐在家裡的計算機面前,登錄到另一臺遠在天涯海角的遠程計算機上。

Java Socket:飛鴿傳書的網絡套接字

在 Windows 系統中,telnet 一般是默認安裝的,但未激活(可以在控制面板中激活它)。

例如,我們 telnet 一下火(shui)土(mu)社區。截圖如下。

Java Socket:飛鴿傳書的網絡套接字

使用 telnet 登錄遠程計算機時,需要遠程計算機上運行一個服務,它一直不停地等待那些希望和它進行連接的網絡請求;當接收到一個客戶端的網絡連接時,它便喚醒正在監聽網絡連接請求的服務器進程,併為兩者建立連接。連接會一直保持,直到某一方中止。

不過,需要注意的是,telnet 在格外重視安全的現代網絡技術中並不受到重用。因為 telnet 是一個明文傳輸協議,用戶的所有內容(包括用戶名和密碼)都沒有經過加密,安全隱患非常大。

02、Socket 實例

不知道你有沒有體驗一下 telnet 火土社區的那條命令,結果非常有趣。我們也可以通過 Java 的客戶端套接字(Socket)實現,代碼示例如下。

try (Socket socket = new Socket("bbs.newsmth.net", 23);) {
InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(is, "gbk");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

1)建立套接字連接非常簡單,只需要一行代碼:

Socket socket = new Socket(host, port)


host 為主機名,port 為端口號(23 為默認的 telnet 端口號)。如果無法確定主機的 IP 地址,則拋出 UnknownHostException 異常;如果在創建套接字時發生 IO 錯誤,則拋出 IOException 異常。

需要注意的是,套接字在建立的時候,如果遠程主機不可訪問,這段代碼就會阻塞很長時間,直到底層操作系統的限制而拋出異常。所以一般會在套接字建立後設置一個超時時間。

Socket socket = new Socket(...);
socket.setSoTimeout(10000); // 單位為毫秒

2)套接字連接成功後,可以通過 java.net.Socket 類的 getInputStream() 方法獲取輸入流。有了 InputStream 對象後,可以藉助文本掃描器類(Scanner)將其中的內容打印出來。

InputStream is = socket.getInputStream();
Scanner scanner = new Scanner(is, "gbk");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}

部分結果(完整結果自己親手實踐一下哦)如下圖所示:

Java Socket:飛鴿傳書的網絡套接字

03、ServerSocket 實例

接下來,我們模擬一個遠程服務,通過 java.net.ServerSocket 實現。代碼示例如下。

try (ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
Scanner scanner = new Scanner(is)) {
PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "gbk"), true);
pw.println("你好啊,歡迎關注「沉默王二」 公眾號,回覆關鍵字「2048」 領取程序員進階必讀資料包");
boolean done = false;
while (!done && scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
if ("2048".equals(line)) {
done = true;
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

1)建立服務器端的套接字也比較簡單,只需要指定一個能夠獨佔的端口號就可以了(0~1023 這些端口都已經被系統預留了)。

ServerSocket server = new ServerSocket(8888);


2)調用 ServerSocket 對象的 accept() 等待客戶端套接字的連接請求。一旦監聽到客戶端的套接字請求,就會返回一個表示連接已建立的 Socket 對象,可以從中獲取到輸入流和輸出流。

Socket socket = server.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();

客戶端套接字發送的所有信息都會包裹在服務器端套接字的輸入流中;而服務器端套接字發送的所有信息都會包裹在客戶端套接字的輸出流中。

3)服務器端可以通過以下代碼向客戶端發送消息。

PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "gbk"), true);
pw.println("你好啊,歡迎關注「沉默王二」 公眾號,回覆關鍵字「2048」 領取程序員進階必讀資料包");

4)服務器端可以通過以下代碼讀取客戶端發送過來的消息。

Scanner scanner = new Scanner(is);
boolean done = false;
while (!done && scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
if ("2048".equals(line)) {
done = true;
}
}

運行該服務後,可以通過 telnet localhost 8888 命令連接該遠程服務,不出所料,你將會看到以下信息。

Java Socket:飛鴿傳書的網絡套接字


PS:可以在當前命令窗口中輸入 2048,服務端收到該消息後會中斷該套接字連接(當前窗口會顯示“遺失對主機的連接”)。

04、為多個客戶端服務

非常遺憾的是,上面的例子中,服務器端只能為一個客戶端服務——這不符合服務器端一對多的要求。

優化方案也非常簡單(你應該也能想得到):服務器端接收到客戶端的套接字請求時,可以啟動一個線程來處理,而主程序繼續等待下一個連接。代碼示例如下。

try (ServerSocket server = new ServerSocket(8888)) {
while (true) {
Socket socket = server.accept();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 套接字處理程序
}
});
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}

線程內部(run(){} 方法裡)用來處理套接字,代碼示例如下:

try {
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
Scanner scanner = new Scanner(is);
// 其他代碼省略
// 向客戶端發送消息
// 讀取客戶端發送過來的消息
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

服務器端代碼優化後重新運行,你就可以通過 telnet 命令測試了。打開一個命令行窗口輸入 telnet localhost 8888,再打開一個新的命令行窗口輸入 telnet localhost 8888,多個窗口都可以和服務器端進行通信,除非服務器端代碼中斷運行。

05、最後

如今大多數基於網絡的軟件,如瀏覽器、即時通訊工具甚至是 P2P 下載都是基於 Socket 實現的,所以掌握 Java Socket 編程還是蠻有必要的。Socket 編程也比較有趣,很多初學者都會編寫一兩個基於“客戶端-服務器端”的小程序來提高自己的編程水平,建議你也試一試。

免費分享Java技術教程,需要的朋友可以在關注後私信我

Java Socket:飛鴿傳書的網絡套接字

原文:https://mp.weixin.qq.com/s/JGIlw4T6F8janikvPP9jWA

作者:沉默王二

來源:微信公眾號

"

相關推薦

推薦中...