中國(guó)紀(jì)檢監(jiān)察報(bào)網(wǎng)站關(guān)鍵詞查詢工具
計(jì)算機(jī)應(yīng)用實(shí)現(xiàn)了多臺(tái)計(jì)算機(jī)間的互聯(lián),使得它們彼此之間能夠進(jìn)行數(shù)據(jù)交流。網(wǎng)絡(luò)應(yīng)用程序就是在已連接的不同計(jì)算機(jī)上運(yùn)行的程序,這些程序借助于網(wǎng)絡(luò)協(xié)議,相互之間可以交換數(shù)據(jù)。編寫網(wǎng)絡(luò)應(yīng)用程序前,首先必須明確所要使用的網(wǎng)絡(luò)協(xié)議。TCP/IP協(xié)議是網(wǎng)絡(luò)應(yīng)用程序的首選
21.1 網(wǎng)絡(luò)程序設(shè)計(jì)基礎(chǔ)
網(wǎng)絡(luò)程序設(shè)計(jì)編寫的是與其他計(jì)算機(jī)進(jìn)行通信的程序。Java已經(jīng)將網(wǎng)絡(luò)程序所需要的元素封裝成不同的類,用戶只要?jiǎng)?chuàng)建這些類的對(duì)象,使用相應(yīng)的方法,即使不具備有關(guān)的網(wǎng)絡(luò)知識(shí),也可以編寫出高質(zhì)量的網(wǎng)絡(luò)通信程序。
21.1.1 局域網(wǎng)與互聯(lián)網(wǎng)
為了實(shí)現(xiàn)兩臺(tái)計(jì)算機(jī)的通信,必須用一個(gè)網(wǎng)絡(luò)線路連接兩臺(tái)計(jì)算機(jī)
服務(wù)器是指提供信息的計(jì)算機(jī)或程序,客戶機(jī)是指請(qǐng)求信息的計(jì)算機(jī)或程序。網(wǎng)絡(luò)用于連接服務(wù)器與客戶機(jī),實(shí)現(xiàn)兩者間的相互通信。但是,有時(shí)在某個(gè)網(wǎng)絡(luò)中很難將服務(wù)器與客戶機(jī)區(qū)分開(kāi)。我們通常所說(shuō)的局域網(wǎng)(Local Area Network,LAN),就是一群通過(guò)一定形式連接起來(lái)的計(jì)算機(jī),它可以由兩臺(tái)計(jì)算機(jī)組成,也可以由同一區(qū)域內(nèi)的上千臺(tái)計(jì)算機(jī)組成。將LAN延伸到更大的范圍,這樣的網(wǎng)絡(luò)稱為廣域網(wǎng)(Wide Area Network,WAN)。我們熟悉的互聯(lián)網(wǎng)(Internet),就是由無(wú)數(shù)的LAN和WAN組成的。
21.1.2 網(wǎng)絡(luò)協(xié)議
網(wǎng)絡(luò)協(xié)議規(guī)定了計(jì)算機(jī)之間連接的物理、機(jī)械(網(wǎng)線與網(wǎng)卡的連接規(guī)定)、電氣(有效的電平范圍)等特征,計(jì)算機(jī)之間的相互尋址規(guī)則,數(shù)據(jù)發(fā)送沖突的解決方式,長(zhǎng)數(shù)據(jù)如何分段傳送與接收等內(nèi)容。就像不同的國(guó)家有不同的法律一樣,目前網(wǎng)絡(luò)協(xié)議也有多種。下面簡(jiǎn)單地介紹幾個(gè)常用的網(wǎng)絡(luò)協(xié)議。
1.IP協(xié)議
IP是Internet Protocol的簡(jiǎn)稱,是一種網(wǎng)絡(luò)協(xié)議。Internet網(wǎng)絡(luò)采用的協(xié)議是TCP/IP協(xié)議,其全稱是Transmission Control Protocol/Internet Protocol。Internet依靠TCP/IP協(xié)議,在全球范圍內(nèi)實(shí)現(xiàn)了不同硬件結(jié)構(gòu)、不同操作系統(tǒng)、不同網(wǎng)絡(luò)系統(tǒng)間的互聯(lián)。在Internet網(wǎng)絡(luò)上存在著數(shù)以億計(jì)的主機(jī),每臺(tái)主機(jī)都用網(wǎng)絡(luò)為其分配的Internet地址代表自己,這個(gè)地址就是IP地址。到目前為止,IP地址用4個(gè)字節(jié),也就是32位的二進(jìn)制數(shù)來(lái)表示,稱為IPv4。為了便于使用,通常取用每個(gè)字節(jié)的十進(jìn)制數(shù),并且每個(gè)字節(jié)之間用圓點(diǎn)隔開(kāi)來(lái)表示IP地址,如192.168.1.1?,F(xiàn)在人們正在試驗(yàn)使用16個(gè)字節(jié)來(lái)表示IP地址,這就是IPv6,但I(xiàn)Pv6還沒(méi)有投入使用。
TCP/IP模式是一種層次結(jié)構(gòu),共分為4層,分別為應(yīng)用層、傳輸層、互聯(lián)網(wǎng)層和網(wǎng)絡(luò)層。各層實(shí)現(xiàn)特定的功能,提供特定的服務(wù)和訪問(wèn)接口,并具有相對(duì)的獨(dú)立性。
2.TCP與UDP協(xié)議
在TCP/IP協(xié)議棧中,有兩個(gè)高級(jí)協(xié)議是網(wǎng)絡(luò)應(yīng)用程序編寫者應(yīng)該了解的,即傳輸控制協(xié)議(Transmission Control Protocol,TCP)與用戶數(shù)據(jù)報(bào)協(xié)議(User Datagram Protocol,UDP)。
TCP協(xié)議是一種以固接連線為基礎(chǔ)的協(xié)議,它提供兩臺(tái)計(jì)算機(jī)間可靠的數(shù)據(jù)傳送。TCP可以保證數(shù)據(jù)從一端送至連接的另一端時(shí),能夠確實(shí)送達(dá),而且抵達(dá)的數(shù)據(jù)的排列順序和送出時(shí)的順序相同。因此,TCP協(xié)議適合可靠性要求比較高的場(chǎng)合。就像撥打電話,必須先撥號(hào)給對(duì)方,等兩端確定連接后,相互才能聽(tīng)到對(duì)方說(shuō)話,也知道對(duì)方回應(yīng)的是什么。
HTTP、FTP和Telnet等都需要使用可靠的通信頻道。例如,HTTP從某個(gè)URL讀取數(shù)據(jù)時(shí),如果收到的數(shù)據(jù)順序與發(fā)送時(shí)不相同,可能就會(huì)出現(xiàn)一個(gè)混亂的HTML文件或是一些無(wú)效的信息。
UDP是無(wú)連接通信協(xié)議,不保證數(shù)據(jù)的可靠傳輸,但能夠向若干個(gè)目標(biāo)發(fā)送數(shù)據(jù),或接收來(lái)自若干個(gè)源的數(shù)據(jù)。UDP以獨(dú)立發(fā)送數(shù)據(jù)包的方式進(jìn)行。這種方式就像郵遞員送信給收信人,可以寄出很多信給同一個(gè)人,且每一封信都是相對(duì)獨(dú)立的,各封信送達(dá)的順序并不重要,收信人接收信件的順序也不能保證與寄出信件的順序相同。
UDP協(xié)議適合于一些對(duì)數(shù)據(jù)準(zhǔn)確性要求不高,但對(duì)傳輸速度和時(shí)效性要求非常高的網(wǎng)站,如網(wǎng)絡(luò)聊天室、在線影片等。這是由于TCP協(xié)議在認(rèn)證上存在額外耗費(fèi),可能使傳輸速度減慢,而UDP協(xié)議即使有一小部分?jǐn)?shù)據(jù)包遺失或傳送順序有所不同,也不會(huì)嚴(yán)重危害該項(xiàng)通信。
注意
一些防火墻和路由器會(huì)設(shè)置成不允許UDP數(shù)據(jù)包傳輸,因此若遇到UDP連接方面的問(wèn)題,應(yīng)先確定所在網(wǎng)絡(luò)是否允許UDP協(xié)議。
21.1.3 端口與套接字
一般而言,一臺(tái)計(jì)算機(jī)只有單一的連到網(wǎng)絡(luò)的物理連接(Physical Connection),所有的數(shù)據(jù)都通過(guò)此連接對(duì)內(nèi)、對(duì)外送達(dá)特定的計(jì)算機(jī),這就是端口。網(wǎng)絡(luò)程序設(shè)計(jì)中的端口(port)并非真實(shí)的物理存在,而是一個(gè)假想的連接裝置。端口被規(guī)定為一個(gè)在0~65535的整數(shù)。HTTP服務(wù)一般使用80端口,FTP服務(wù)使用21端口。假如一臺(tái)計(jì)算機(jī)提供了HTTP、FTP等多種服務(wù),那么客戶機(jī)會(huì)通過(guò)不同的端口來(lái)確定連接到服務(wù)器的哪項(xiàng)服務(wù)上,如圖21.3所示。
通常,0~1023的端口數(shù)用于一些知名的網(wǎng)絡(luò)服務(wù)和應(yīng)用,用戶的普通網(wǎng)絡(luò)應(yīng)用程序應(yīng)該使用1024以上的端口數(shù),以避免端口號(hào)與另一個(gè)應(yīng)用或系統(tǒng)服務(wù)所用端口沖突。
網(wǎng)絡(luò)程序中的套接字(Socket)用于將應(yīng)用程序與端口連接起來(lái)。套接字是一個(gè)假想的連接裝置,就像插座一樣可連接電器與電線,如圖21.4所示。Java將套接字抽象化為類,程序設(shè)計(jì)者只需創(chuàng)建Socket類對(duì)象,即可使用套接字。
21.2 TCP程序
TCP網(wǎng)絡(luò)程序設(shè)計(jì)是指利用Socket類編寫通信程序。利用TCP協(xié)議進(jìn)行通信的兩個(gè)應(yīng)用程序是有主次之分的,一個(gè)稱為服務(wù)器程序,另一個(gè)稱為客戶機(jī)程序,兩者的功能和編寫方法大不一樣。
①——服務(wù)器程序創(chuàng)建一個(gè)ServerSocket(服務(wù)器端套接字)對(duì)象,調(diào)用accept()方法等待客戶機(jī)來(lái)連接。
②——客戶端程序創(chuàng)建一個(gè)Socket對(duì)象,請(qǐng)求與服務(wù)器建立連接。
③——服務(wù)器接收客戶機(jī)的連接請(qǐng)求,同時(shí)創(chuàng)建一個(gè)新的Socket對(duì)象與客戶建立連接。隨后服務(wù)器繼續(xù)等待新的請(qǐng)求。
21.2.1 InetAddress類
java.net包中的InetAddress類是與IP地址相關(guān)的類,利用該類可以獲取IP地址、主機(jī)地址等信息。
?使用InetAddress類的getHostName()和getHostAddress()方法獲得本地主機(jī)的本機(jī)名、本機(jī)IP地址。
注意
InetAddress類的方法會(huì)拋出UnknownHostException異常,所以必須進(jìn)行異常處理。這個(gè)異常在主機(jī)不存在或網(wǎng)絡(luò)連接錯(cuò)誤時(shí)發(fā)生。
21.2.2 ServerSocket類
java.net包中的ServerSocket類用于表示服務(wù)器套接字,其主要功能是等待來(lái)自網(wǎng)絡(luò)上的“請(qǐng)求”,它可通過(guò)指定的端口來(lái)等待連接的套接字。服務(wù)器套接字一次可以與一個(gè)套接字連接。如果多臺(tái)客戶機(jī)同時(shí)提出連接請(qǐng)求,服務(wù)器套接字會(huì)將請(qǐng)求連接的客戶機(jī)存入列隊(duì)中,然后從中取出一個(gè)套接字,與服務(wù)器新建的套接字連接起來(lái)。若請(qǐng)求連接數(shù)大于最大容納數(shù),則多出的連接請(qǐng)求被拒絕。隊(duì)列的默認(rèn)大小是50。
ServerSocket類的構(gòu)造方法通常會(huì)拋出IOException異常,具體有以下幾種形式:
?ServerSocket():創(chuàng)建非綁定服務(wù)器套接字。
ServerSocket(int port):創(chuàng)建綁定到特定端口的服務(wù)器套接字。
ServerSocket(int port, int backlog):利用指定的backlog創(chuàng)建服務(wù)器套接字,并將其綁定到指定的本地端口號(hào)上。
ServerSocket(int port, int backlog, InetAddress bindAddress):使用指定的端口、偵聽(tīng)backlog和要綁定到的本地IP地址創(chuàng)建服務(wù)器。這種情況適用于計(jì)算機(jī)上有多塊網(wǎng)卡和多個(gè)IP地址的情況,用戶可以明確規(guī)定ServerSocket在哪塊網(wǎng)卡或哪個(gè)IP地址上等待客戶的連接請(qǐng)求。
調(diào)用ServerSocket類的accept()方法,會(huì)返回一個(gè)和客戶端Socket對(duì)象相連接的Socket對(duì)象。服務(wù)器端的Socket對(duì)象使用getOutputStream()方法獲得的輸出流,將指向客戶端Socket對(duì)象使用getInputStream()方法獲得的那個(gè)輸入流;同樣,服務(wù)器端的Socket對(duì)象使用getInputStream()方法獲得的輸入流,將指向客戶端Socket對(duì)象使用getOutputStream()方法獲得的那個(gè)輸出流。也就是說(shuō),當(dāng)服務(wù)器向輸出流寫入信息時(shí),客戶端通過(guò)相應(yīng)的輸入流就能讀取,反之亦然。
注意
accept()方法會(huì)阻塞線程的繼續(xù)執(zhí)行,直到接收到客戶的呼叫。如果沒(méi)有客戶呼叫服務(wù)器,那么System.out.println("連接中")語(yǔ)句將不會(huì)執(zhí)行。語(yǔ)句如果沒(méi)有客戶請(qǐng)求,accept()方法沒(méi)有發(fā)生阻塞,肯定是程序出現(xiàn)了問(wèn)題。通常是使用了一個(gè)被其他程序占用的端口號(hào),ServerSocket綁定沒(méi)有成功。
yu = server.accept();
System.out.println("連接中");
21.2.3 TCP網(wǎng)絡(luò)程序設(shè)計(jì)
明白了TCP程序工作的過(guò)程,就可以編寫TCP服務(wù)器程序了。在網(wǎng)絡(luò)編程中,如果只要求客戶機(jī)向服務(wù)器發(fā)送消息,不要求服務(wù)器向客戶機(jī)發(fā)送消息,稱為單向通信??蛻魴C(jī)套接字
和服務(wù)器套接字連接成功后,客戶機(jī)通過(guò)輸出流發(fā)送數(shù)據(jù),服務(wù)器則通過(guò)輸入流接收數(shù)據(jù)。下面是簡(jiǎn)單的單向通信的實(shí)例。
【例21.2】創(chuàng)建TCP/IP協(xié)議服務(wù)器
運(yùn)行服務(wù)器端程序,將輸出提示信息,等待客戶呼叫。下面再來(lái)看一下客戶端程序。
編寫客戶端程序,將用戶在文本框中輸入的信息發(fā)送至服務(wù)器端,并將文本框中輸入的信息顯示在客戶端的文本域中。
說(shuō)明
當(dāng)一臺(tái)機(jī)器上安裝了多個(gè)網(wǎng)絡(luò)應(yīng)用程序時(shí),很可能指定的端口號(hào)已被占用。還可能遇到以前運(yùn)行良好的網(wǎng)絡(luò)程序突然運(yùn)行不了的情況,這種情況很可能也是由于端口被別的程序占用了。此時(shí)可以運(yùn)行netstat-help來(lái)獲得幫助,使用netstat-an命令來(lái)查看該程序所使用的端口
21.3 UDP程序
用戶數(shù)據(jù)報(bào)協(xié)議(UDP)是網(wǎng)絡(luò)信息傳輸?shù)牧硪环N形式?;赨DP的通信和基于TCP的通信不同,基于UDP的信息傳遞更快,但不提供可靠性保證。使用UDP傳遞數(shù)據(jù)時(shí),用戶無(wú)法知道數(shù)據(jù)能否正確地到達(dá)主機(jī),也不能確定到達(dá)目的地的順序是否和發(fā)送的順序相同。雖然UDP是一種不可靠的協(xié)議,但如果需要較快地傳輸信息,并能容忍小的錯(cuò)誤,可以考慮使用UDP。
基于UDP通信的基本模式如下:
將數(shù)據(jù)打包(稱為數(shù)據(jù)包),然后將數(shù)據(jù)包發(fā)往目的地。
接收別人發(fā)來(lái)的數(shù)據(jù)包,然后查看數(shù)據(jù)包。
發(fā)送數(shù)據(jù)包的步驟如下:
(1)使用DatagramSocket()創(chuàng)建一個(gè)數(shù)據(jù)包套接字。
(2)使用DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)創(chuàng)建要發(fā)送的數(shù)據(jù)包。
(3)使用DatagramSocket類的send()方法發(fā)送數(shù)據(jù)包。
接收數(shù)據(jù)包的步驟如下:
(1)使用DatagramSocket(int port)創(chuàng)建數(shù)據(jù)包套接字,綁定到指定的端口。
(2)使用DatagramPacket(byte[] buf, int length)創(chuàng)建字節(jié)數(shù)組來(lái)接收數(shù)據(jù)包。
(3)使用DatagramPacket類的receive()方法接收UDP包。
注意
DatagramSocket類的receive()方法接收數(shù)據(jù)時(shí),如果還沒(méi)有可以接收的數(shù)據(jù),在正常情況下receive()方法將阻塞,一直等到網(wǎng)絡(luò)上有數(shù)據(jù)傳來(lái),receive()方法接收該數(shù)據(jù)并返回。如果網(wǎng)絡(luò)上沒(méi)有數(shù)據(jù)發(fā)送過(guò)來(lái),receive()方法也沒(méi)有阻塞,肯定是程序有問(wèn)題,大多數(shù)情況下是因?yàn)槭褂昧艘粋€(gè)被其他程序占用的端口號(hào)。
21.3.1 DatagramPacket類
java.net包的DatagramPacket類用來(lái)表示數(shù)據(jù)包。DatagramPacket類的構(gòu)造方法如下:
DatagramPacket(byte[] buf, int length)。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)。
第一種構(gòu)造方法在創(chuàng)建DatagramPacket對(duì)象時(shí),指定了數(shù)據(jù)包的內(nèi)存空間和大小。第二種構(gòu)造方法不僅指定了數(shù)據(jù)包的內(nèi)存空間和大小,還指定了數(shù)據(jù)包的目標(biāo)地址和端口。在發(fā)
送數(shù)據(jù)時(shí),必須指定接收方的Socket地址和端口號(hào),因此使用第二種構(gòu)造方法可創(chuàng)建發(fā)送數(shù)據(jù)的DatagramPacket對(duì)象。
21.3.2 DatagramSocket類
java.net包中的DatagramSocket類用于表示發(fā)送和接收數(shù)據(jù)包的套接字。該類的構(gòu)造方法如下:
DatagramSocket()。
DatagramSocket(int port)。
DatagramSocket(int port, InetAddress addr)。
第一種構(gòu)造方法創(chuàng)建DatagramSocket對(duì)象,構(gòu)造數(shù)據(jù)報(bào)套接字,并將其綁定到本地主機(jī)任何可用的端口上。第二種構(gòu)造方法創(chuàng)建DatagramSocket對(duì)象,創(chuàng)建數(shù)據(jù)報(bào)套接字,并將其綁定到本地主機(jī)的指定端口上。第三種構(gòu)造方法創(chuàng)建DatagramSocket對(duì)象,創(chuàng)建數(shù)據(jù)報(bào)套接字,并將其綁定到指定的端口和指定的本地地址上。第三種構(gòu)造函數(shù)適用于有多塊網(wǎng)卡和多個(gè)IP地址的情況。
如果接收數(shù)據(jù)時(shí)必須指定一個(gè)端口號(hào),不允許系統(tǒng)隨機(jī)產(chǎn)生,此時(shí)可以使用第二種構(gòu)造方法。比如有個(gè)朋友要你給他寫信,那他的地址就必須確定,不確定是不行的。在發(fā)送數(shù)據(jù)時(shí)通常使用第一種構(gòu)造方法,不指定端口號(hào),而是系統(tǒng)為我們分配一個(gè)端口號(hào),就像寄信不需要到指定的郵局去寄一樣。
21.3.3 UDP網(wǎng)絡(luò)程序設(shè)計(jì)
根據(jù)前面所講的網(wǎng)絡(luò)編程的基本知識(shí)以及UDP網(wǎng)絡(luò)編程的特點(diǎn),下面創(chuàng)建一個(gè)廣播數(shù)據(jù)報(bào)程序。廣播數(shù)據(jù)報(bào)是一項(xiàng)較新的技術(shù),其原理類似于電臺(tái)廣播。廣播電臺(tái)需要在指定的波段和頻率上廣播信息,收聽(tīng)者也要將收音機(jī)調(diào)到指定的波段、頻率,才可以收聽(tīng)廣播內(nèi)容。
【例21.3】創(chuàng)建UDP協(xié)議廣播電臺(tái)程序接收廣播程序。單擊“開(kāi)始接收”按鈕,系統(tǒng)開(kāi)始接收主機(jī)播出的信息;單擊“停止接收”按鈕,系統(tǒng)停止接收廣播主機(jī)播出的信息。代碼如下:
說(shuō)明
發(fā)出廣播和接收廣播的主機(jī)地址必須位于同一個(gè)組內(nèi),地址范圍為224.0.0.0~224.255.255.255,該地址并不代表某個(gè)特定主機(jī)的位置。加入同一個(gè)組的主機(jī)可以在某個(gè)端口上廣播信息,也可以在某個(gè)端口上接收信息。
?