更新時間:2022-06-21 12:36:21 來源:動力節(jié)點 瀏覽1529次
客戶端和服務(wù)器是套接字編程的兩個主要組件。客戶端是請求服務(wù)的計算機/節(jié)點,服務(wù)器是響應(yīng)客戶端的計算機/節(jié)點。在 Java 中,使用套接字編程,我們可以連接客戶端和服務(wù)器。
套接字是用于發(fā)送和接收消息的端點。它是 IP 地址和端口號的組合。客戶端-服務(wù)器程序中使用了兩種類型的套接字:一種是客戶端套接字,另一種是服務(wù)器套接字。在客戶端-服務(wù)器程序中,客戶端必須知道客戶端想要發(fā)送服務(wù)請求的服務(wù)器端點的位置(IP 地址和端口號)。在計算機世界中,客戶端和服務(wù)器都是應(yīng)用程序。服務(wù)器程序使用服務(wù)器套接字,而客戶端程序使用客戶端套接字進行通信。
以下 Java 程序說明了如何在客戶端和服務(wù)器之間建立通信。讓我們從客戶端程序開始。
// 導(dǎo)入語句
導(dǎo)入java.net.*;
導(dǎo)入java.io.*;
導(dǎo)入 java.util.Scanner;
公共類客戶端
{
// 初始化套接字和輸入輸出流
私有數(shù)據(jù)輸出流數(shù)據(jù)輸出 = null;
私人掃描儀 sc = null;
私有套接字 skt = null;
// 構(gòu)造函數(shù)來創(chuàng)建具有給定 IP 和端口地址的套接字
公共客戶端(字符串地址,int 端口)
{
// 與服務(wù)器建立連接
嘗試
{
// 創(chuàng)建一個socket對象
skt = 新套接字(地址,端口);
System.out.println("連接建立!!");
System.out.println("輸入 \"Finish\" 終止連接。");
// 從用戶那里獲取輸入
sc = 新掃描儀(System.in);
// 在套接字上打開輸出流
dataOut = new DataOutputStream(skt.getOutputStream());
}
catch(UnknownHostException 呃)
{
System.out.println(uh);
}
捕捉(IOException io)
{
System.out.println(io);
}
// 存儲用戶輸入的信息
字符串 str = "";
// 繼續(xù)讀取直到輸入“Finish”
而(!str.equals(“完成”))
{
輸入 = sc.nextLine(); // 讀取輸入
嘗試
{
dataOut.writeUTF(str); // 寫入底層輸出流
}
// 用于在寫入輸出流時處理錯誤
捕捉(IOException io)
{
System.out.println(io);
}
}
System.out.println("連接終止!!");
// 用于關(guān)閉連接
嘗試
{
數(shù)據(jù)輸出.close();
skt.close();
}
捕捉(IOException io)
{
System.out.println(io);
}
}
公共靜態(tài)無效主要(字符串a(chǎn)rgvs [])
{
// 創(chuàng)建類Client的對象
ClientSide client = new ClientSide("localhost", 6666);
}
}
解釋:我們知道要建立連接,客戶端和服務(wù)器端都需要套接字。以下語句在客戶端創(chuàng)建一個套接字:
sk = 新套接字(地址,端口);
Socket 類的構(gòu)造函數(shù)有兩個參數(shù):一個是地址(IP 地址),另一個是端口(端口號),并創(chuàng)建了 Socket 類的對象。在代碼中,我們使用了端口號 6666。這里,我們使用了 localhost,因為客戶端應(yīng)用程序和服務(wù)器應(yīng)用程序運行在同一個系統(tǒng)上。通常,客戶端程序和服務(wù)器程序位于不同的系統(tǒng)上。在這種情況下,使用運行服務(wù)器的系統(tǒng)的 IP 地址而不是 localhost。確保在這種情況下使用完全限定的 IP 地址/名稱。
端口號 6666 表示客戶端正在嘗試在端口 6666 上建立與服務(wù)器的連接。如果服務(wù)器在端口 6666 上,則連接建立;否則,不是。
該聲明
dataOut = new DataOutputStream(skt.getOutputStream());
dataOut.writeUTF(str);
寫入在套接字上打開的輸出流。服務(wù)器正在讀取輸出流上寫入的任何內(nèi)容。這里,str是一個字符串,它讀取用戶輸入的任何內(nèi)容。變量str的讀取將繼續(xù),直到用戶輸入“Finish”。如果在寫入底層流時發(fā)生任何錯誤,IOException的 catch 塊就會出現(xiàn)。
如果我們在 Socket 類的構(gòu)造函數(shù)的參數(shù)中提供任何無效的 IP 地址,則上述 catch 塊的以下代碼片段將生效。
catch(UnknownHostException 呃)
{
System.out.println(uh);
}
例如,如果我們鍵入“locahost”而不是“localhost”,則上述 catch 塊的語句將生效。
現(xiàn)在,讓我們討論一下服務(wù)器端程序。
// 導(dǎo)入語句
導(dǎo)入java.net.*;
導(dǎo)入java.io.*;
公共類服務(wù)器
{
//初始化輸入流和套接字
私有數(shù)據(jù)輸入流 inStream = null;
私有套接字 skt = null;
私有 ServerSocket srvr = null;
// 類Server的構(gòu)造函數(shù)
公共服務(wù)器(int 端口)
{
// 啟動服務(wù)器并等待客戶端
嘗試
{
srvr = 新服務(wù)器套接字(端口);
System.out.println("服務(wù)器啟動");
System.out.println("正在等待客戶端連接...");
skt = srvr.accept(); // 等待客戶端發(fā)送連接請求
System.out.println("與客戶端連接!!");
// 使用套接字接收來自客戶端的輸入消息
inStream = new DataInputStream(skt.getInputStream());
字符串 str = ""; // 用于讀取客戶端發(fā)送的消息的變量
// 直到客戶端發(fā)送“完成”,
// 繼續(xù)閱讀消息
而(!str.equals(“完成”))
{
嘗試
{
// 從底層流中讀取
str = inStream.readUTF();
// 在控制臺上打印讀取的消息
System.out.println(str);
}
// 用于處理錯誤
捕捉(IOException io)
{
System.out.println(io);
}
}
//關(guān)閉已建立的連接
skt.close();
inStream.close();
System.out.println("連接關(guān)閉!!");
}
// 處理錯誤
捕獲(IOException 我)
{
System.out.println(i);
}
}
公共靜態(tài)無效主要(字符串a(chǎn)rgvs [])
{
// 創(chuàng)建類ServerSide的對象
服務(wù)器服務(wù)器=新服務(wù)器(6666);
}
}
解釋:聲明
srvr = 新服務(wù)器套接字(端口);
創(chuàng)建一個新套接字并將其綁定到端口號,該端口號作為參數(shù)(端口)傳遞給類ServerSocket的構(gòu)造函數(shù)。在代碼中,我們使用了端口號 6666。這意味著服務(wù)器正在偵聽端口號 6666,客戶端必須使用此端口號(6666)連接到服務(wù)器。
該聲明
skt = srvr.accept();
服務(wù)器使用它來接受來自客戶端的連接請求。服務(wù)器在調(diào)用方法accept() 后等待。等待一直持續(xù)到服務(wù)器從客戶端收到連接請求。在這里,等待意味著在accept()方法之后編寫的任何語句在服務(wù)器收到連接請求之前不會被執(zhí)行。在這個位置,我們說服務(wù)器正在監(jiān)聽給定的端口號,在我們的例子中是 6666。
為了讀取客戶端發(fā)送的消息,我們必須打開一個到套接字的輸入流。以下語句也是如此。
inStream = new DataInputStream(skt.getInputStream());
getInputStream()方法返回附加到套接字的輸入流。在 Java 中,數(shù)據(jù)輸出流用于寫入可以稍后由輸入流讀取的數(shù)據(jù)。上述聲明中也發(fā)生了同樣的情況。當(dāng)我們調(diào)用DataInputStream類的readUTF()方法時,我們從客戶端發(fā)送的任何內(nèi)容都會被讀取。下面的語句做同樣的事情
str = inStream.readUTF();
在客戶端,我們使用writeUTF()方法對流進行寫入部分。同樣,在服務(wù)器端,我們在這里使用了 readUTF() 從流中讀取部分。readUTF ()方法返回一個 Unicode 字符串,我們將其存儲在變量str 中。繼續(xù)閱讀,直到客戶端發(fā)送“完成”一詞。閱讀“完成”一詞后,連接將關(guān)閉。下面的書面陳述達(dá)到了同樣的效果。
skt.close();
inStream.close();
執(zhí)行步驟
首先,應(yīng)該執(zhí)行服務(wù)器端程序。這是因為,當(dāng)我們開始執(zhí)行客戶端程序時,它開始在端口號 6666 處尋找服務(wù)器。由于我們沒有先執(zhí)行服務(wù)器端程序,因此不會有服務(wù)器在偵聽端口號 6666。因此,客戶端程序引發(fā)NullPointerException。因此,客戶端程序必須在服務(wù)器端程序執(zhí)行之后執(zhí)行。
為了執(zhí)行上述程序,打開兩個命令提示符,一個用于客戶端程序,另一個用于服務(wù)器端程序。分別使用命令javac和java進行編譯和執(zhí)行。
輸出:
首先,我們執(zhí)行服務(wù)器端程序。
我們看到執(zhí)行后,服務(wù)器等待客戶端連接。現(xiàn)在,執(zhí)行客戶端程序并觀察服務(wù)器如何響應(yīng)。
我們看到服務(wù)器響應(yīng)消息Connected with a client!! 現(xiàn)在,連接已經(jīng)建立,我們可以向連接的服務(wù)器發(fā)送消息。觀察以下快照。
1234, 78, ..., Russia 是客戶端發(fā)送的輸入。這些輸入消息在服務(wù)器端顯示。要終止連接,我們必須輸入單詞 Finish。
輸入“完成”一詞后,兩邊的連接都關(guān)閉了。
相關(guān)閱讀
初級 202925
初級 203221
初級 202629
初級 203743