更新時(shí)間:2022-04-01 11:05:26 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽5130次
Java 有大量有用的網(wǎng)絡(luò)庫(kù)供您使用。在本文中,我將向您展示如何制作一個(gè)可以在您的計(jì)算機(jī)上運(yùn)行的簡(jiǎn)單 Java 服務(wù)器。我們的服務(wù)器會(huì)做一些事情。我們連接的那一刻,它會(huì)打印字符串“Hello!”,它還應(yīng)該讓我們選擇通過(guò)輸入“Peace”來(lái)終止連接。本教程的目標(biāo)是向您展示一些有用的 Java 庫(kù)來(lái)實(shí)現(xiàn)這一點(diǎn)!在創(chuàng)建服務(wù)器時(shí),實(shí)際上需要考慮 4 個(gè)主要步驟。
在實(shí)現(xiàn)服務(wù)器的核心細(xì)節(jié)之前,我們需要找到一種方法來(lái)確定我們將如何連接到服務(wù)器。這很重要,因?yàn)樗肓巳齻€(gè)核心網(wǎng)絡(luò)概念;ip-address,端口和套接字。不要害怕這些術(shù)語(yǔ),我會(huì)盡力在下面解釋它們。
IP 地址——在最簡(jiǎn)單的形式中,IP 地址只是表示網(wǎng)絡(luò)中特定計(jì)算機(jī)地址的一種奇特方式。這由一個(gè)特定的數(shù)字表示,例如 192.168.11.11。這是一個(gè)唯一的 ID,互聯(lián)網(wǎng)上的所有其他機(jī)器都可以通過(guò)它來(lái)識(shí)別您的計(jì)算機(jī)。在我們的例子中,我們將在我們的機(jī)器上運(yùn)行我們的服務(wù)器,這意味著連接不必通過(guò)互聯(lián)網(wǎng)再回到我們的機(jī)器,相反,操作系統(tǒng)足夠智能,可以在我們的機(jī)器內(nèi)路由請(qǐng)求,而無(wú)需與網(wǎng)絡(luò)交互。對(duì)于這種情況,有一個(gè)專(zhuān)門(mén)用于此的特殊 IP 地址;127.0.0.1 或有時(shí)稱(chēng)為 localhost。如果您在 Linux 終端中鍵入ip address,您將看到計(jì)算機(jī)上的網(wǎng)絡(luò)設(shè)備列表。第一個(gè)是環(huán)回設(shè)備,此設(shè)備允許您計(jì)算機(jī)中的任何服務(wù)與您機(jī)器中的其他服務(wù)進(jìn)行通信,您的操作系統(tǒng)將使用環(huán)回地址 127.0.0.1 在您的機(jī)器內(nèi)路由它,而不是通過(guò)網(wǎng)絡(luò)發(fā)送它。
端口- 一旦我們有了相關(guān)計(jì)算機(jī)的地址,我們就需要能夠連接到該計(jì)算機(jī)上我們想要的服務(wù)。這就是端口的用武之地。端口就像在提供某些服務(wù)的計(jì)算機(jī)上運(yùn)行的進(jìn)程,所以一旦您確定了正確的計(jì)算機(jī)(使用 IP 地址),我們必須選擇端口才能連接到該計(jì)算機(jī)中的正確服務(wù)。
套接字- 到目前為止,我們可以使用 ip 地址在網(wǎng)絡(luò)/互聯(lián)網(wǎng)中定位計(jì)算機(jī)。我們可以使用端口識(shí)別我們想要連接到的計(jì)算機(jī)中的哪個(gè)服務(wù),但是我們?nèi)匀恍枰谝慌_(tái)計(jì)算機(jī)和我們的目標(biāo)計(jì)算機(jī)之間建立連接。這就是套接字的用武之地。套接字可以在網(wǎng)絡(luò)中的兩臺(tái)計(jì)算機(jī)之間實(shí)現(xiàn)完全的雙向通信。如您所料,套接字需要目標(biāo)計(jì)算機(jī)的地址和端口才能創(chuàng)建連接
現(xiàn)在我們已經(jīng)掌握了網(wǎng)絡(luò)的基礎(chǔ)知識(shí),讓我們來(lái)創(chuàng)建服務(wù)器吧!讓我們從創(chuàng)建連接開(kāi)始。記住連接是使用套接字創(chuàng)建的。
EC-1:創(chuàng)建連接
公共靜態(tài)無(wú)效 連接服務(wù)器() {
嘗試(服務(wù)器套接字服務(wù)器套接字= new ServerSocket(9991)) {
套接字連接套接字=服務(wù)器套接字。接受();
在 EC-1 中,我們創(chuàng)建了一個(gè)方法connectToServer,在這個(gè)方法中,我們有一個(gè)不完整的嘗試語(yǔ)句,它執(zhí)行以下操作:
(1)創(chuàng)建一個(gè)ServerSocket
(2)指定此服務(wù)將在其上運(yùn)行的端口 9991
(3)接受 ServerSocket 連接!
和沙贊!我們已經(jīng)建立了我們的聯(lián)系,并且至少建立了聯(lián)系的基礎(chǔ)。我們還沒(méi)有連接到任何東西。在 Java 中,aServerSocket只是等待連接,一旦連接,接收一些任意輸入,處理該輸入,然后返回響應(yīng)!在我們的例子中,我們的服務(wù)器只會(huì)回顯您選擇輸入的任何內(nèi)容!根據(jù) 的定義ServerSocket,它需要等待連接,在EC-1中,最后一行接受該連接,我們將其保存在一個(gè)名為connectionSocketthat 的變量中,該變量的類(lèi)型為Socket。
太棒了,所以我們已經(jīng)完成了連接框架的鋪設(shè)。讓我們的服務(wù)器交互,允許它在我們連接時(shí)進(jìn)行通信!
為了與我們的服務(wù)器來(lái)回交互,我們需要一種方法來(lái)使用我們剛剛在 EC-1 中設(shè)置的連接來(lái)來(lái)回傳輸信息。一種很好的方法是使用IOStreams,在我們的例子中是 JavaInputStream和OutputStream類(lèi)。這些將允許進(jìn)出服務(wù)器的雙向通信。讓我們?cè)贓C-1中實(shí)現(xiàn)它
EC-2:實(shí)現(xiàn) IOStream
...
InputStream inputToServer = connectionSocket .getInputStream();
OutputStream outputFromServer = connectionSocket .getOutputStream();
在EC-2中,我們創(chuàng)建了InputStream一個(gè)從上面創(chuàng)建的輸入connectionSocket,我們還創(chuàng)建OutputStream一個(gè)從connectionSocket. 輸入流代表我們將發(fā)送到服務(wù)器的內(nèi)容,所以它是inputToServer,而輸出代表服務(wù)器的輸出。
EC-3:將 IOStreams 轉(zhuǎn)化為實(shí)際可用數(shù)據(jù)
...
Scanner scanner = new Scanner( inputToServer , "UTF-8");
PrintWriter serverPrintOut = new PrintWriter(new OutputStreamWriter( outputFromServer , "UTF-8"), true);
serverPrintOut .println("你好!輸入和平退出。");
在EC-3中,我們采用IOStreams在EC-2中創(chuàng)建的并使用它們。我們首先創(chuàng)建一個(gè)Scanner,掃描器將接收服務(wù)器的輸入并將其轉(zhuǎn)換為服務(wù)器可以讀取的形式。然后我們創(chuàng)建一個(gè)PrintWriter,PrintWriter它將從服務(wù)器獲取輸出并將其打印在我們的屏幕上。創(chuàng)建Scanner和PrintWriter是必不可少的,因?yàn)镋C-2IOStreams中的單獨(dú)僅表示傳輸中的數(shù)據(jù),它們不會(huì)打印或?qū)?shù)據(jù)轉(zhuǎn)換為服務(wù)器和用戶(hù)理解的格式。為了讓我們看到我們已經(jīng)連接到服務(wù)器,服務(wù)器應(yīng)該通過(guò)打印 Hello! 來(lái)通知我們。連接時(shí)給我們。
回顧一下,我們現(xiàn)在可以連接到我們的服務(wù)器(EC-1) ,通過(guò)IOStreams (EC-2)從服務(wù)器發(fā)送和接收信息,并且可以將流轉(zhuǎn)換為服務(wù)器和用戶(hù)的相關(guān)輸出(EC-3)。
服務(wù)器可以做很多事情,但它仍然不能做一些基本的事情,比如向我們實(shí)際打印數(shù)據(jù),甚至在客戶(hù)端請(qǐng)求時(shí)終止連接。我們將在這里實(shí)現(xiàn)邏輯。
EC-4: 服務(wù)器邏輯
boolean done = false;
while(! done &&掃描儀.hasNextLine()) {
字符串行=掃描儀.nextLine();
serverPrintOut .println("<您的姓名>服務(wù)器回顯:" + line );
if( line .toLowerCase().trim().equals("peace")) {
done = true;
}
}
在EC-4中,我們需要一種方法來(lái)檢查客戶(hù)端是否完成了連接。我們首先創(chuàng)建一個(gè)boolean名為的標(biāo)志done并將其設(shè)置為false. 然后我們創(chuàng)建一個(gè) while 循環(huán),它熱切地觀察done值是否變?yōu)?true,它還會(huì)檢查EC-3Scanner中創(chuàng)建的是否仍然正常運(yùn)行并且可以接受輸入。
我們服務(wù)器的作用是打印回我們輸入的任何內(nèi)容,Scanner該類(lèi)檢查用戶(hù)是否發(fā)送了新行,我們使用該輸入作為服務(wù)器的輸出,前綴為“Echo from <Your Name Here> Server: ”.
最后,我們需要找到一種方法來(lái)根據(jù)客戶(hù)端請(qǐng)求實(shí)際終止連接。因此,如果客戶(hù)端鍵入單詞“peace”,代碼會(huì)將 done 標(biāo)志更改為 true,while 循環(huán)條件將不再滿足,它將終止循環(huán)和應(yīng)用程序。
所以我們現(xiàn)在已經(jīng)制作了簡(jiǎn)單的 Hello 服務(wù)器,這是一個(gè)包含所有代碼在一個(gè)方法中的要點(diǎn)!
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* Written by Martin Ombura Jr. <@martinomburajr>
*/
public class MyServer {
public static void main(String[] args) {
connectToServer();
}
public static void connectToServer() {
//Try connect to the server on an unused port eg 9991. A successful connection will return a socket
try(ServerSocket serverSocket = new ServerSocket(9991)) {
Socket connectionSocket = serverSocket.accept();
//Create Input&Outputstreams for the connection
InputStream inputToServer = connectionSocket.getInputStream();
OutputStream outputFromServer = connectionSocket.getOutputStream();
Scanner scanner = new Scanner(inputToServer, "UTF-8");
PrintWriter serverPrintOut = new PrintWriter(new OutputStreamWriter(outputFromServer, "UTF-8"), true);
serverPrintOut.println("Hello World! Enter Peace to exit.");
//Have the server take input from the client and echo it back
//This should be placed in a loop that listens for a terminator text e.g. bye
boolean done = false;
while(!done && scanner.hasNextLine()) {
String line = scanner.nextLine();
serverPrintOut.println("Echo from <Your Name Here> Server: " + line);
if(line.toLowerCase().trim().equals("peace")) {
done = true;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
是時(shí)候投入我們所有的工作并運(yùn)行這段代碼了。
(1)如何連接
1)從您的 Java IDE 或命令行運(yùn)行此 Java 應(yīng)用程序服務(wù)器代碼。
2)為了讓您連接到服務(wù)器,您需要一個(gè)可以讓您執(zhí)行此操作的工具。在 Linux 和 Mac 上,隨意使用netcat或telnet任何其他您想要的連接協(xié)議,如果您沒(méi)有它們,請(qǐng)?jiān)诠雀杷阉魅绾卧谀牟僮飨到y(tǒng)版本上安裝它們。對(duì)于 Windows,有幾個(gè)工具以及winrs. 命令如下
NetCat:這是一種流行的網(wǎng)絡(luò)實(shí)用程序,用于連接到網(wǎng)站、服務(wù)器等。
數(shù)控 127.0.0.1 9991
Telnet: Telnet 是一種舊的雙向互聯(lián)網(wǎng)連接協(xié)議。它非常簡(jiǎn)單,將通過(guò)未加密的連接發(fā)送數(shù)據(jù)。這意味著您在傳遞敏感信息時(shí)應(yīng)避免使用它。但是對(duì)于這個(gè)簡(jiǎn)單的例子,它是有效的。
遠(yuǎn)程登錄 127.0.0.1 9991
Curl: Curl 與上面的兩個(gè)有點(diǎn)不同,因?yàn)樗鼘⒁跃W(wǎng)頁(yè)格式連接到服務(wù)器。這樣做的缺點(diǎn)是,一旦連接,可能不容易將文本直接發(fā)送到 curl,因此您無(wú)法通過(guò)鍵入“再見(jiàn)”來(lái)終止連接。
telnet 127.0.0.1 9991
(2)一旦連接
一旦連接!你應(yīng)該有一些看起來(lái)像這樣的東西。
隨意玩耍并輸入內(nèi)容,
輸入“peace”關(guān)閉連接
當(dāng)你玩它的時(shí)候,嘗試重新啟動(dòng)連接,添加更多連接等。你會(huì)注意到這些重要的點(diǎn):
(1)這個(gè)服務(wù)器只能處理一個(gè)連接,所以到它的多個(gè)連接將被取消。在以后的文章中,我們將讓這個(gè)服務(wù)器并發(fā),允許它處理多個(gè)連接。
(2)如果客戶(hù)端,即你,終止連接,套接字關(guān)閉,連接中斷,程序結(jié)束,這意味著你不能在不重新啟動(dòng)應(yīng)用程序的情況下再次連接到服務(wù)器。
本文的目的是玩轉(zhuǎn) Java 使用的一些很酷的網(wǎng)絡(luò)特性!如您所見(jiàn),可能性是無(wú)窮無(wú)盡的。我們可以以一種可能基于我們提供的輸入數(shù)據(jù)執(zhí)行數(shù)學(xué)計(jì)算的方式對(duì)我們的服務(wù)器進(jìn)行編碼,或者我們的服務(wù)器可以是數(shù)據(jù)庫(kù)之間的中介,它會(huì)執(zhí)行諸如檢索、驗(yàn)證、操作或清理數(shù)據(jù)庫(kù)信息之類(lèi)的操作輸入。機(jī)會(huì)無(wú)窮無(wú)盡!
相關(guān)閱讀
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743