Java程序员从笨鸟到菜鸟之(十三)java网络通信编程
首先聲明一下,剛開(kāi)始學(xué)習(xí)Java網(wǎng)絡(luò)通信編程就對(duì)他有一種畏懼感,因?yàn)樽约簩?duì)網(wǎng)絡(luò)一竅不通,所以。。。呵呵。。你懂得,昨天又仔細(xì)的學(xué)習(xí)了一遍,感覺(jué)其實(shí)java網(wǎng)絡(luò)編程也沒(méi)想象的那么難,不信,咱一起看看。。。呵呵。。
?????網(wǎng)絡(luò)編程就是在兩個(gè)或兩個(gè)以上的設(shè)備(例如計(jì)算機(jī))之間傳輸數(shù)據(jù)。程序員所作的事情就是把數(shù)據(jù)發(fā)送到指定的位置,或者接收到指定的數(shù)據(jù),這個(gè)就是狹義的網(wǎng)絡(luò)編程范疇。在發(fā)送和接收數(shù)據(jù)時(shí),大部分的程序設(shè)計(jì)語(yǔ)言都設(shè)計(jì)了專(zhuān)門(mén)的API實(shí)現(xiàn)這些功能,程序員只需要調(diào)用即可。所以,基礎(chǔ)的網(wǎng)絡(luò)編程可以和打電話(huà)一樣簡(jiǎn)單
一:首先看一下網(wǎng)絡(luò)通訊的兩種方式
1.TCP(傳輸控制協(xié)議)方式
TCP方式就類(lèi)似于撥打電話(huà),使用該種方式進(jìn)行網(wǎng)絡(luò)通訊時(shí),需要建立專(zhuān)門(mén)的虛擬連接,然后進(jìn)行可靠的數(shù)據(jù)傳輸,如果數(shù)據(jù)發(fā)送失敗,則客戶(hù)端會(huì)自動(dòng)重發(fā)該數(shù)據(jù)
2.?UDP(用戶(hù)數(shù)據(jù)報(bào)協(xié)議)方式
?????UDP方式就類(lèi)似于發(fā)送短信,使用這種方式進(jìn)行網(wǎng)絡(luò)通訊時(shí),不需要建立專(zhuān)門(mén)的虛擬連接,傳輸也不是很可靠,如果發(fā)送失敗則客戶(hù)端無(wú)法獲得
?這兩種傳輸方式都是實(shí)際的網(wǎng)絡(luò)編程中進(jìn)行使用,重要的數(shù)據(jù)一般使用TCP方式進(jìn)行數(shù)據(jù)傳輸,而大量的非核心數(shù)據(jù)則都通過(guò)UDP方式進(jìn)行傳遞,在一些程序中甚至結(jié)合使用這兩種方式進(jìn)行數(shù)據(jù)的傳遞。由于TCP需要建立專(zhuān)用的虛擬連接以及確認(rèn)傳輸是否正確,所以使用TCP方式的速度稍微慢一些,而且傳輸時(shí)產(chǎn)生的數(shù)據(jù)量要比UDP稍微大一些。
總結(jié)一下UDP和TCP協(xié)議的區(qū)別
-使用UDP時(shí),每個(gè)數(shù)據(jù)報(bào)中都給出了完整的地址信息,因此無(wú)需要建立發(fā)送方和接收方的連接。?
–對(duì)于TCP協(xié)議,由于它是一個(gè)面向連接的協(xié)議,在socket之間進(jìn)行數(shù)據(jù)傳輸之前必然要建立連接,所以在TCP中多了一個(gè)連接建立的時(shí)間?
–使用UDP傳輸數(shù)據(jù)時(shí)是有大小限制的,每個(gè)被傳輸?shù)臄?shù)據(jù)報(bào)必須限定在64KB之內(nèi)。?
–TCP沒(méi)有這方面的限制,一旦連接建立起來(lái),雙方的socket就可以按統(tǒng)一的格式傳輸大量的數(shù)據(jù)。?
–UDP是一個(gè)不可靠的協(xié)議,發(fā)送方所發(fā)送的數(shù)據(jù)報(bào)并不一定以相同的次序到達(dá)接收方。?
–TCP是一個(gè)可靠的協(xié)議,它確保接收方完全正確地獲取發(fā)送方所發(fā)送的全部數(shù)據(jù)?
-TCP在網(wǎng)絡(luò)通信上有極強(qiáng)的生命力,例如遠(yuǎn)程連接(Telnet)和文件傳輸(FTP)都需要不定長(zhǎng)度的數(shù)據(jù)被可靠地傳輸。?
—相比之下UDP操作簡(jiǎn)單,而且僅需要較少的監(jiān)護(hù),因此通常用于局域網(wǎng)高可靠性的分散系統(tǒng)中client/server應(yīng)用程序?
二:基于url的網(wǎng)絡(luò)編程
1.創(chuàng)建一個(gè)URL
為了表示URL,?java.Net中實(shí)現(xiàn)了類(lèi)URL。我們可以通過(guò)下面的構(gòu)造方法來(lái)初始化一個(gè)URL對(duì)象:
(1)?public?URL?(String?spec);
通過(guò)一個(gè)表示URL地址的字符串可以構(gòu)造一個(gè)URL對(duì)象
URL?urlBase=new?URL("http://www.?263.net/")
? (2)?public?URL(URL?context,?String?spec);
通過(guò)基URL和相對(duì)URL構(gòu)造一個(gè)URL對(duì)象。
URL?net263=new?URL?("http://www.263.net/");
URL?index263=new?URL(net263,?"index.html")
(3)?public?URL(String?protocol,?String?host,?String?file);
new?URL("http",?"www.gamelan.com",?"/pages/Gamelan.net.?html");
(4)?public?URL(String?protocol,?String?host,?int?port,?String?file);
URL?gamelan=new?URL("http",?"www.gamelan.com",?80,?"Pages/Gamelan.network.html");
注意:類(lèi)URL的構(gòu)造方法都聲明拋棄非運(yùn)行時(shí)例外(MalformedURLException),因此生成URL對(duì)象時(shí),我們必須要對(duì)這一例外進(jìn)行處理,通常是用try-catch語(yǔ)句進(jìn)行捕獲。格式如下:
try{
URL?myURL=?new?URL(…)
}catch?(MalformedURLException?e){
… }
2.?解析一個(gè)URL
一個(gè)URL對(duì)象生成后,其屬性是不能被改變的,但是我們可以通過(guò)類(lèi)URL所提供的方法來(lái)獲取這些屬性:
public?String?getProtocol()?獲取該URL的協(xié)議名。
public?String?getHost()?獲取該URL的主機(jī)名。
public?int?getPort()?獲取該URL的端口號(hào),如果沒(méi)有設(shè)置端口,返回-1。
public?String?getFile()?獲取該URL的文件名。
public?String?getRef()?獲取該URL在文件中的相對(duì)位置。
public?String?getQuery()?獲取該URL的查詢(xún)信息。
public?String?getPath()?獲取該URL的路徑
??public?String?getAuthority()?獲取該URL的權(quán)限信息
public?String?getUserInfo()?獲得使用者的信息
?public?String?getRef()獲得該URL的錨
3.從URL讀取WWW網(wǎng)絡(luò)資源
當(dāng)我們得到一個(gè)URL對(duì)象后,就可以通過(guò)它讀取指定的WWW資源。這時(shí)我們將使用URL的方法openStream(),其定義為:
InputStream?openStream();
方法openSteam()與指定的URL建立連接并返回InputStream類(lèi)的對(duì)象以從這一連接中讀取數(shù)據(jù)。
URL?url?=?new?URL("http://www.baidu.com");
//使用openStream得到一輸入流并由此構(gòu)造一個(gè)BufferedReader對(duì)象
BufferedReader?br?=?new?BufferedReader(new?InputStreamReader( url.openStream()));
String?line?=?null;
while(null?!=?(line?=?br.readLine()))
{
System.out.println(line);
}
br.close();
三:客戶(hù)端網(wǎng)絡(luò)編程步驟
按照前面的基礎(chǔ)知識(shí)介紹,無(wú)論使用TCP方式還是UDP方式進(jìn)行網(wǎng)絡(luò)通訊,網(wǎng)絡(luò)編程都是由客戶(hù)端和服務(wù)器端組成
1.客戶(hù)端網(wǎng)絡(luò)編程步驟
????????客戶(hù)端(Client)是指網(wǎng)絡(luò)編程中首先發(fā)起連接的程序,客戶(hù)端一般實(shí)現(xiàn)程序界面和基本邏輯實(shí)現(xiàn),在進(jìn)行實(shí)際的客戶(hù)端編程時(shí),無(wú)論客戶(hù)端復(fù)雜還是簡(jiǎn)單,以及客戶(hù)端實(shí)現(xiàn)的方式,客戶(hù)端的編程主要由三個(gè)步驟實(shí)現(xiàn):
1、?建立網(wǎng)絡(luò)連接
客戶(hù)端網(wǎng)絡(luò)編程的第一步都是建立網(wǎng)絡(luò)連接。在建立網(wǎng)絡(luò)連接時(shí)需要指定連接到的服務(wù)器的IP地址和端口號(hào),建立完成以后,會(huì)形成一條虛擬的連接,后續(xù)的操作就可以通過(guò)該連接實(shí)現(xiàn)數(shù)據(jù)交換了。
2、?交換數(shù)據(jù)
連接建立以后,就可以通過(guò)這個(gè)連接交換數(shù)據(jù)了。交換數(shù)據(jù)嚴(yán)格按照請(qǐng)求響應(yīng)模型進(jìn)行,由客戶(hù)端發(fā)送一個(gè)請(qǐng)求數(shù)據(jù)到服務(wù)器,服務(wù)器反饋一個(gè)響應(yīng)數(shù)據(jù)給客戶(hù)端,如果客戶(hù)端不發(fā)送請(qǐng)求則服務(wù)器端就不響應(yīng)。
根據(jù)邏輯需要,可以多次交換數(shù)據(jù),但是還是必須遵循請(qǐng)求響應(yīng)模型。
3、?關(guān)閉網(wǎng)絡(luò)連接
在數(shù)據(jù)交換完成以后,關(guān)閉網(wǎng)絡(luò)連接,釋放程序占用的端口、內(nèi)存等系統(tǒng)資源,結(jié)束網(wǎng)絡(luò)編程。
????????最基本的步驟一般都是這三個(gè)步驟,在實(shí)際實(shí)現(xiàn)時(shí),步驟2會(huì)出現(xiàn)重復(fù),在進(jìn)行代碼組織時(shí),由于網(wǎng)絡(luò)編程是比較耗時(shí)的操作,所以一般開(kāi)啟專(zhuān)門(mén)的現(xiàn)場(chǎng)進(jìn)行網(wǎng)絡(luò)通訊。
2.服務(wù)器端網(wǎng)絡(luò)編程步驟
????????服務(wù)器端(Server)是指在網(wǎng)絡(luò)編程中被動(dòng)等待連接的程序,服務(wù)器端一般實(shí)現(xiàn)程序的核心邏輯以及數(shù)據(jù)存儲(chǔ)等核心功能。服務(wù)器端的編程步驟和客戶(hù)端不同,是由四個(gè)步驟實(shí)現(xiàn),依次是:
1、?監(jiān)聽(tīng)端口
服務(wù)器端屬于被動(dòng)等待連接,所以服務(wù)器端啟動(dòng)以后,不需要發(fā)起連接,而只需要監(jiān)聽(tīng)本地計(jì)算機(jī)的某個(gè)固定端口即可。
這個(gè)端口就是服務(wù)器端開(kāi)放給客戶(hù)端的端口,服務(wù)器端程序運(yùn)行的本地計(jì)算機(jī)的IP地址就是服務(wù)器端程序的IP地址。
2、?獲得連接
當(dāng)客戶(hù)端連接到服務(wù)器端時(shí),服務(wù)器端就可以獲得一個(gè)連接,這個(gè)連接包含客戶(hù)端的信息,例如客戶(hù)端IP地址等等,服務(wù)器端和客戶(hù)端也通過(guò)該連接進(jìn)行數(shù)據(jù)交換。
一般在服務(wù)器端編程中,當(dāng)獲得連接時(shí),需要開(kāi)啟專(zhuān)門(mén)的線程處理該連接,每個(gè)連接都由獨(dú)立的線程實(shí)現(xiàn)。
3、?交換數(shù)據(jù)
服務(wù)器端通過(guò)獲得的連接進(jìn)行數(shù)據(jù)交換。服務(wù)器端的數(shù)據(jù)交換步驟是首先接收客戶(hù)端發(fā)送過(guò)來(lái)的數(shù)據(jù),然后進(jìn)行邏輯處理,再把處理以后的結(jié)果數(shù)據(jù)發(fā)送給客戶(hù)端。簡(jiǎn)單來(lái)說(shuō),就是先接收再發(fā)送,這個(gè)和客戶(hù)端的數(shù)據(jù)交換數(shù)序不同。
其實(shí),服務(wù)器端獲得的連接和客戶(hù)端連接是一樣的,只是數(shù)據(jù)交換的步驟不同。
當(dāng)然,服務(wù)器端的數(shù)據(jù)交換也是可以多次進(jìn)行的。
在數(shù)據(jù)交換完成以后,關(guān)閉和客戶(hù)端的連接。
4、?關(guān)閉連接
當(dāng)服務(wù)器程序關(guān)閉時(shí),需要關(guān)閉服務(wù)器端,通過(guò)關(guān)閉服務(wù)器端使得服務(wù)器監(jiān)聽(tīng)的端口以及占用的內(nèi)存可以釋放出來(lái),實(shí)現(xiàn)了連接的關(guān)閉。
四:一個(gè)基礎(chǔ)的網(wǎng)絡(luò)類(lèi)——InetAddress類(lèi)
????該類(lèi)的功能是代表一個(gè)IP地址,并且將IP地址和域名相關(guān)的操作方法包含在該類(lèi)的內(nèi)部。
????關(guān)于該類(lèi)的使用,下面通過(guò)一個(gè)基礎(chǔ)的代碼示例演示該類(lèi)的使用,代碼如下:
[java]?view plaincopy print?注:InetAddress?類(lèi)沒(méi)有明顯的構(gòu)造函數(shù)。為生成一個(gè)InetAddress對(duì)象,必須運(yùn)用一個(gè)可用的工廠方法。?
–工廠方法(factory?method)僅是一個(gè)類(lèi)中靜態(tài)方法返回一個(gè)該類(lèi)實(shí)例的約定。對(duì)于InetAddress,三個(gè)方法?getLocalHost(?)、getByName(?)以及getAllByName(?)可以用來(lái)創(chuàng)建InetAddress的實(shí)例?
?如果這些方法不能解析主機(jī)名,它們引發(fā)一個(gè)UnknownHostException異常。?
五:TCP編程
在Java語(yǔ)言中,對(duì)于TCP方式的網(wǎng)絡(luò)編程提供了良好的支持,在實(shí)際實(shí)現(xiàn)時(shí),以java.net.Socket類(lèi)代表客戶(hù)端連接,以java.net.ServerSocket類(lèi)代表服務(wù)器端連接。在進(jìn)行網(wǎng)絡(luò)編程時(shí),底層網(wǎng)絡(luò)通訊的細(xì)節(jié)已經(jīng)實(shí)現(xiàn)了比較高的封裝,所以在程序員實(shí)際編程時(shí),只需要指定IP地址和端口號(hào)碼就可以建立連接了。
在客戶(hù)端網(wǎng)絡(luò)編程中,首先需要建立連接,在Java?API中以java.net.Socket類(lèi)的對(duì)象代表網(wǎng)絡(luò)連接
客戶(hù)端
1)?建立Socket連接?
Socket?socket2?=?new?Socket(“www.sohu.com”,80);
2)按照“請(qǐng)求-響應(yīng)”模型進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)交換
在Java語(yǔ)言中,數(shù)據(jù)傳輸功能由Java?IO實(shí)現(xiàn),也就是說(shuō)只需要從連接中獲得輸入流和輸出流即可,然后將需要發(fā)送的數(shù)據(jù)寫(xiě)入連接對(duì)象的輸出流中,在發(fā)送完成以后從輸入流中讀取數(shù)據(jù)即可。示例代碼如下:
?OutputStream?os?=?socket1.getOutputStream();?//獲得輸出流
?InputStream?is?=?socket1.getInputStream();?????//獲得輸入流
這里獲得的只是最基本的輸出流和輸入流對(duì)象,還可以根據(jù)前面學(xué)習(xí)到的IO知識(shí),使用流的嵌套將這些獲得到的基本流對(duì)象轉(zhuǎn)換成需要的裝飾流對(duì)象,從而方便數(shù)據(jù)的操作。
3)關(guān)閉網(wǎng)絡(luò)連接
?socket1.close();
服務(wù)器端
首先需要說(shuō)明的是,客戶(hù)端的步驟和服務(wù)器端的編寫(xiě)步驟不同,所以在學(xué)習(xí)服務(wù)器端編程時(shí)注意不要和客戶(hù)端混淆起來(lái)。
1)監(jiān)聽(tīng)端口
ServerSocket?ss?=?new?ServerSocket(10000);
2)獲得連接
當(dāng)有客戶(hù)端連接到達(dá)時(shí),建立一個(gè)和客戶(hù)端連接對(duì)應(yīng)的Socket連?接對(duì)象,從而釋放客戶(hù)端連接對(duì)于服務(wù)器端端口的占用
Socket?socket?=?ss.accept();
該代碼實(shí)現(xiàn)的功能是獲得當(dāng)前連接到服務(wù)器端的客戶(hù)端連接。需要說(shuō)明的是accept和前面IO部分介紹的read方法一樣,都是一個(gè)阻塞方法,也就是當(dāng)無(wú)連接時(shí),該方法將阻塞程序的執(zhí)行,直到連接到達(dá)時(shí)才執(zhí)行該行代碼。另外獲得的連接會(huì)在服務(wù)器端的該端口注冊(cè),這樣以后就可以通過(guò)在服務(wù)器端的注冊(cè)信息直接通信,而注冊(cè)以后服務(wù)器端的端口就被釋放出來(lái),又可以繼續(xù)接受其它的連接了。
3)按照“請(qǐng)求-響應(yīng)”模型進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)交換
這里獲得的Socket類(lèi)型的連接就和客戶(hù)端的網(wǎng)絡(luò)連接一樣了,只是服務(wù)器端需要首先讀取發(fā)送過(guò)來(lái)的數(shù)據(jù),然后進(jìn)行邏輯處理以后再發(fā)送給客戶(hù)端,也就是交換數(shù)據(jù)的順序和客戶(hù)端交換數(shù)據(jù)的步驟剛好相反
?InputStream?is?=?ss.getInputStream();?????//獲得輸入流
OutputStream?os?=?ss.getOutputStream();?//獲得輸出流
4)關(guān)閉服務(wù)器端連接
ss.close();
以上就是基本的TCP類(lèi)型的服務(wù)器和客戶(hù)端代碼實(shí)現(xiàn)的步驟,下面以一個(gè)簡(jiǎn)單的echo(回聲)服務(wù)實(shí)現(xiàn)為例子,介紹綜合使用示例,實(shí)現(xiàn)的代碼如下:
[java]?view plaincopy print?UDP編程
?????UDP(User?Datagram?Protocol),中文意思是用戶(hù)數(shù)據(jù)報(bào)協(xié)議使用該種方式無(wú)需建立專(zhuān)用的虛擬連接,由于無(wú)需建立專(zhuān)用的連接,所以對(duì)于服務(wù)器的壓力要比TCP小很多,所以也是一種常見(jiàn)的網(wǎng)絡(luò)編程方式。但是使用該種方式最大的不足是傳輸不可靠,當(dāng)然也不是說(shuō)經(jīng)常丟失,就像大家發(fā)短信息一樣,理論上存在收不到的可能
?????在Java?API中,實(shí)現(xiàn)UDP方式的編程,包含客戶(hù)端網(wǎng)絡(luò)編程和服務(wù)器端網(wǎng)絡(luò)編程,主要由兩個(gè)類(lèi)實(shí)現(xiàn),分別是:
l?DatagramSocket
DatagramSocket類(lèi)實(shí)現(xiàn)“網(wǎng)絡(luò)連接”,包括客戶(hù)端網(wǎng)絡(luò)連接和服務(wù)器端網(wǎng)絡(luò)連接。雖然UDP方式的網(wǎng)絡(luò)通訊不需要建立專(zhuān)用的網(wǎng)絡(luò)連接,但是畢竟還是需要發(fā)送和接收數(shù)據(jù),DatagramSocket實(shí)現(xiàn)的就是發(fā)送數(shù)據(jù)時(shí)的發(fā)射器,以及接收數(shù)據(jù)時(shí)的監(jiān)聽(tīng)器的角色。類(lèi)比于TCP中的網(wǎng)絡(luò)連接,該類(lèi)既可以用于實(shí)現(xiàn)客戶(hù)端連接,也可以用于實(shí)現(xiàn)服務(wù)器端連接。
l?DatagramPacket
DatagramPacket類(lèi)實(shí)現(xiàn)對(duì)于網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)封裝,也就是說(shuō),該類(lèi)的對(duì)象代表網(wǎng)絡(luò)中交換的數(shù)據(jù)。在UDP方式的網(wǎng)絡(luò)編程中,無(wú)論是需要發(fā)送的數(shù)據(jù)還是需要接收的數(shù)據(jù),都必須被處理成DatagramPacket類(lèi)型的對(duì)象,該對(duì)象中包含發(fā)送到的地址、發(fā)送到的端口號(hào)以及發(fā)送的內(nèi)容等。其實(shí)DatagramPacket類(lèi)的作用類(lèi)似于現(xiàn)實(shí)中的信件,在信件中包含信件發(fā)送到的地址以及接收人,還有發(fā)送的內(nèi)容等,郵局只需要按照地址傳遞即可。在接收數(shù)據(jù)時(shí),接收到的數(shù)據(jù)也必須被處理成DatagramPacket類(lèi)型的對(duì)象,在該對(duì)象中包含發(fā)送方的地址、端口號(hào)等信息,也包含數(shù)據(jù)的內(nèi)容。和TCP方式的網(wǎng)絡(luò)傳輸相比,IO編程在UDP方式的網(wǎng)絡(luò)編程中變得不是必須的內(nèi)容,結(jié)構(gòu)也要比TCP方式的網(wǎng)絡(luò)編程簡(jiǎn)單一些。
UDP客戶(hù)端編程涉及的步驟也是4個(gè)部分:建立連接、發(fā)送數(shù)據(jù)、接收數(shù)據(jù)和關(guān)閉連接。
1)建立連接:
DatagramSocket?ds?=?new?DatagramSocket();
該客戶(hù)端連接使用系統(tǒng)隨機(jī)分配的一個(gè)本地計(jì)算機(jī)的未用端口號(hào)
?當(dāng)然,可以通過(guò)制定連接使用的端口號(hào)來(lái)創(chuàng)建客戶(hù)端連接。
??DatagramSocket?ds?=?new?DatagramSocket(5000);
一般在建立客戶(hù)端連接時(shí)沒(méi)有必要指定端口號(hào)碼。
2)發(fā)送數(shù)據(jù)
在發(fā)送數(shù)據(jù)時(shí),需要將需要發(fā)送的數(shù)據(jù)內(nèi)容首先轉(zhuǎn)換為byte數(shù)組,然后將數(shù)據(jù)內(nèi)容、服務(wù)器IP和服務(wù)器端口號(hào)一起構(gòu)造成一個(gè)DatagramPacket類(lèi)型的對(duì)象,這樣數(shù)據(jù)的準(zhǔn)備就完成了了,發(fā)送時(shí)調(diào)用網(wǎng)絡(luò)連接對(duì)象中的send方法發(fā)送該對(duì)象即可
代碼示例:
[java]?view plaincopy print?
?
??????在該示例代碼中,不管發(fā)送的數(shù)據(jù)內(nèi)容是什么,都需要轉(zhuǎn)換為byte數(shù)組,然后將服務(wù)器端的IP地址構(gòu)造成InetAddress類(lèi)型的對(duì)象,在準(zhǔn)備完成以后,將這些信息構(gòu)造成一個(gè)DatagramPacket類(lèi)型的對(duì)象,在UDP編程中,發(fā)送的數(shù)據(jù)內(nèi)容、服務(wù)器端的IP和端口號(hào),都包含在DatagramPacket對(duì)象中。在準(zhǔn)備完成以后,調(diào)用連接對(duì)象ds的send方法把DatagramPacket對(duì)象發(fā)送出去即可。
3)UDP客戶(hù)端編程中接收數(shù)據(jù)
?????首先構(gòu)造一個(gè)數(shù)據(jù)緩沖數(shù)組,該數(shù)組用于存儲(chǔ)接收的服務(wù)器端反饋數(shù)據(jù),該數(shù)組的長(zhǎng)度必須大于或等于服務(wù)器端反饋的實(shí)際有效數(shù)據(jù)的長(zhǎng)度。然后以該緩沖數(shù)組為基礎(chǔ)構(gòu)造一個(gè)DatagramPacket數(shù)據(jù)包對(duì)象,最后調(diào)用連接對(duì)象的receive方法接收數(shù)據(jù)即可。接收到的服務(wù)器端反饋數(shù)據(jù)存儲(chǔ)在DatagramPacket類(lèi)型的對(duì)象內(nèi)部
示例代碼:
[java]?view plaincopy print?
?
代碼講解?:??首先構(gòu)造緩沖數(shù)組data,這里設(shè)置的長(zhǎng)度1024是預(yù)估的接收到的數(shù)據(jù)長(zhǎng)度,要求該長(zhǎng)度必須大于或等于接收到的數(shù)據(jù)長(zhǎng)度,然后以該緩沖數(shù)組為基礎(chǔ),構(gòu)造數(shù)據(jù)包對(duì)象,使用連接對(duì)象ds的receive方法接收反饋數(shù)據(jù),由于在Java語(yǔ)言中,除String以外的其它對(duì)象都是按照地址傳遞,所以在receive方法內(nèi)部可以改變數(shù)據(jù)包對(duì)象receiveDp的內(nèi)容,這里的receiveDp的功能和返回值類(lèi)似。數(shù)據(jù)接收到以后,只需要從數(shù)據(jù)包對(duì)象中讀取出來(lái)就可以了,使用DatagramPacket對(duì)象中的getData方法可以獲得數(shù)據(jù)包對(duì)象的緩沖區(qū)數(shù)組,但是緩沖區(qū)數(shù)組的長(zhǎng)度一般大于有效數(shù)據(jù)的長(zhǎng)度,換句話(huà)說(shuō),也就是緩沖區(qū)數(shù)組中只有一部分?jǐn)?shù)據(jù)是反饋數(shù)據(jù),所以需要使用DatagramPacket對(duì)象中的getLength方法獲得有效數(shù)據(jù)的長(zhǎng)度,則有效數(shù)據(jù)就是緩沖數(shù)組中的前有效數(shù)據(jù)長(zhǎng)度個(gè)內(nèi)容,這些才是真正的服務(wù)器端反饋的數(shù)據(jù)的內(nèi)容
4)關(guān)閉連接
??ds.close();
UDP方式服務(wù)器端網(wǎng)絡(luò)編程
1)首先UDP方式服務(wù)器端網(wǎng)絡(luò)編程需要建立一個(gè)連接,該連接監(jiān)聽(tīng)某個(gè)端口:
?DatagramSocket?ds?=?new?DatagramSocket(10010);
由于服務(wù)器端的端口需要固定,所以一般在建立服務(wù)器端連接時(shí),都指定端口號(hào)
2)接收客戶(hù)端發(fā)送過(guò)來(lái)的數(shù)據(jù)
其接收的方法和客戶(hù)端接收的方法一直,其中receive方法的作用類(lèi)似于TCP方式中accept方法的作用,該方法也是一個(gè)阻塞方法,其作用是接收數(shù)據(jù)。
ds.receive()
接收到客戶(hù)端發(fā)送過(guò)來(lái)的數(shù)據(jù)以后,服務(wù)器端對(duì)該數(shù)據(jù)進(jìn)行邏輯處理,然后將處理以后的結(jié)果再發(fā)送給客戶(hù)端,在這里發(fā)送時(shí)就比客戶(hù)端要麻煩一些,因?yàn)榉?wù)器端需要獲得客戶(hù)端的IP和客戶(hù)端使用的端口號(hào),這個(gè)都可以從接收到的數(shù)據(jù)包中獲得。示例代碼如下:
?????//獲得客戶(hù)端的IP
?????InetAddress?clientIP?=?receiveDp.getAddress();
?????????//獲得客戶(hù)端的端口號(hào)
?????????Int?clientPort?=?receiveDp.getPort();
3)關(guān)閉連接
ds.close()
??????? 好了,占時(shí)就總結(jié)到這吧,總結(jié)的不是很全面,但很基礎(chǔ),應(yīng)該適合初學(xué)者學(xué)習(xí),由于本人也是初學(xué)者的小菜鳥(niǎo),所有很多東西可能都涉及不到,希望大家見(jiàn)諒!
?
?本文來(lái)自:曹勝歡博客專(zhuān)欄。轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/csh624366188
總結(jié)
以上是生活随笔為你收集整理的Java程序员从笨鸟到菜鸟之(十三)java网络通信编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java程序员从笨鸟到菜鸟之(十二)ja
- 下一篇: Java程序员从笨鸟到菜鸟之(七十)细谈