《Java網(wǎng)絡(luò)程序設(shè)計》課件-第5章_第1頁
《Java網(wǎng)絡(luò)程序設(shè)計》課件-第5章_第2頁
《Java網(wǎng)絡(luò)程序設(shè)計》課件-第5章_第3頁
《Java網(wǎng)絡(luò)程序設(shè)計》課件-第5章_第4頁
《Java網(wǎng)絡(luò)程序設(shè)計》課件-第5章_第5頁
已閱讀5頁,還剩71頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第5章TCPSocket

5.1套接字5.2TCPSocket5.3多線程操作

5.1套接字

5.1.1端口的概念

在TCP/IP體系結(jié)構(gòu)中,傳輸層為應(yīng)用層提供傳輸服務(wù),可選擇TCP和UDP兩個傳輸協(xié)議充當(dāng)數(shù)據(jù)的承載協(xié)議。應(yīng)用層通過傳輸層進(jìn)行數(shù)據(jù)通信時,TCP和UDP會遇到同時為多個應(yīng)用程序進(jìn)程提供并發(fā)服務(wù)的問題。在TCP/IP協(xié)議中為應(yīng)用層和傳輸層之間提出了端口(port)的概念,用于標(biāo)識網(wǎng)絡(luò)主機(jī)上的唯一通信進(jìn)程。

端口指網(wǎng)絡(luò)體系結(jié)構(gòu)中應(yīng)用層與傳輸層之間的通信協(xié)議接口,也稱為傳輸層服務(wù)訪問接口。端口是一種抽象的軟件結(jié)構(gòu),包括一些數(shù)據(jù)結(jié)構(gòu)和I/O緩沖區(qū)。應(yīng)用進(jìn)程通過系統(tǒng)調(diào)用與某端口建立關(guān)聯(lián)(binding)后,傳輸層傳給該端口的數(shù)據(jù)都被相應(yīng)的應(yīng)用進(jìn)程所接收。TCP與UDP的端口如圖5-1所示。圖5-1TCP與UDP的端口(a)數(shù)據(jù)發(fā)送;(b)數(shù)據(jù)接收端口號使用16位表示,取值范圍為0~65?535,含義是一臺使用TCP/IP體系結(jié)構(gòu)的計算機(jī)上最多在應(yīng)用層上區(qū)別65?336個TCP網(wǎng)絡(luò)進(jìn)程和65?336個UDP網(wǎng)絡(luò)進(jìn)程,實際上不能達(dá)到這樣多的進(jìn)程數(shù)量。所有的端口僅具有本地意義,即端口僅能設(shè)置本地的網(wǎng)絡(luò)通信進(jìn)程,而不能設(shè)置通信對方的應(yīng)用進(jìn)程端口號。表5-1列出了部分基于TCP的常用應(yīng)用進(jìn)程的端口號。習(xí)慣上,端口號可分為三大類:

(1)公認(rèn)端口(WellKnownPorts):從0~1023,它們緊密綁定于一些服務(wù)。通常這些端口的通信明確表明了某種服務(wù)的協(xié)議。例如:80端口實際上總是綁定HTTP通信。

(2)注冊端口(RegisteredPorts):從1024~49?151,它們松散地綁定于一些服務(wù)。也就是說有許多服務(wù)綁定于這些端口,這些端口同樣用于許多其他目的。例如:許多系統(tǒng)處理動態(tài)端口從1024左右開始。

(3)動態(tài)或私有端口(DynamicandorPrivatePorts):從49?152~65?535。理論上,從1024起為服務(wù)分配動態(tài)端口,但也有例外,如Sun的RPC端口從32?768開始。5.1.2套接字的概念

套接字(Socket)原意是“插座”,在計算機(jī)網(wǎng)絡(luò)中指支持TCP/IP的網(wǎng)絡(luò)通信的基本操作單元,可以被看做是兩個進(jìn)程在通信連接中的一個端點,是連接應(yīng)用程序和網(wǎng)絡(luò)驅(qū)動程序的橋梁。Socket在應(yīng)用進(jìn)程中創(chuàng)建,通過綁定與網(wǎng)絡(luò)驅(qū)動建立關(guān)系。此后,應(yīng)用進(jìn)程送給Socket的數(shù)據(jù),由Socket傳遞給網(wǎng)絡(luò)驅(qū)動程序向網(wǎng)絡(luò)上發(fā)送出去。計算機(jī)從網(wǎng)絡(luò)上收到與該Socket綁定IP地址和端口號相關(guān)的數(shù)據(jù)后,由網(wǎng)絡(luò)驅(qū)動進(jìn)程交給Socket,應(yīng)用進(jìn)程便可從該Socket中提取接收到的數(shù)據(jù),即網(wǎng)絡(luò)應(yīng)用進(jìn)程通過Socket實現(xiàn)數(shù)據(jù)的發(fā)送與接收。在同一臺主機(jī)上可能會同時運行多個應(yīng)用進(jìn)程,為了區(qū)分不同應(yīng)用進(jìn)程的網(wǎng)絡(luò)通信和連接,Socket通過三個參數(shù)唯一地標(biāo)識本地主機(jī)上的通信進(jìn)程,實現(xiàn)與網(wǎng)絡(luò)進(jìn)程的綁定關(guān)系,這三個參數(shù)分別是:通信的目的IP地址、使用的傳輸層協(xié)議(TCP或UDP)以及使用的端口號。此時,應(yīng)用層和傳輸層就可以通過Socket,區(qū)分來自不同應(yīng)用程序進(jìn)程或網(wǎng)絡(luò)連接的通信,實現(xiàn)數(shù)據(jù)傳輸?shù)牟l(fā)服務(wù)。

以最常見的WWW訪問為例,例如:在瀏覽器地址中輸入了網(wǎng)頁URL地址:

/index.html該URL就包含了套接字的三個參數(shù),由于采用超文本傳輸協(xié)議(HyperTextTransferProtocol,HTTP)說明使用的是TCP協(xié)議;根據(jù)目標(biāo)網(wǎng)頁的域名“”,可以通過域名服務(wù)器查找到該WWW服務(wù)器的IP地址為;通常在訪問URL時,如端口無特殊指定時,默認(rèn)使用80;index.html說明訪問的文件資源。所以,訪問該網(wǎng)頁時的套接字為{TCP,,80}。5.1.3Netstat的應(yīng)用

由于在TCP/IP體系結(jié)構(gòu)中通過端口唯一標(biāo)識主機(jī)上的應(yīng)用通信進(jìn)程,因而可以通過查看本地端口信息掌握本地主機(jī)的網(wǎng)絡(luò)進(jìn)程運行情況;即:用戶可以知道本地計算機(jī)開放了哪些通信端口,都是什么軟件進(jìn)程開的;可以掌握開放的端口處于什么狀態(tài),是等待連接還是已經(jīng)連接,如果是已經(jīng)連接,需要特別注意看連接是個正常連接還是非正常連接,例如木馬等;可以知道目前本機(jī)是不是正在和其他計算機(jī)交換數(shù)據(jù),是正常的程序訪問到一個正常網(wǎng)站還是訪問到一個陷阱,更重要的是因為端口只能唯一地標(biāo)識通信進(jìn)程,通過查看本地的端口使用情況,可以避免產(chǎn)生端口使用沖突的問題。在Windows操作系統(tǒng)中,提供了工具軟件Netstat.exe。它可以用于顯示與IP,TCP,UDP和ICMP等協(xié)議相關(guān)的統(tǒng)計數(shù)據(jù),通常被用于檢驗本機(jī)各端口的網(wǎng)絡(luò)連接情況。在這里列舉Netstat常用的參數(shù)?-a和?-n,如:

●?Netstat-a 本選項顯示一個有效連接信息列表,包括已建立的TCP連接(ESTABLISHED),也包括TCP監(jiān)聽連接請求(LISTENING)的連接。

●?Netstat-n 顯示所有已建立的有效連接,包括基于TCP和UDP的應(yīng)用進(jìn)程。

通常,將?-a和?-n聯(lián)合執(zhí)行,即Netstat-an,即可列出本地計算機(jī)所有的占用端口情況。所有的端口必然處于下列狀態(tài)之一:●?LISTENING狀態(tài),表示某個端口是個開放的TCP端口,正處于監(jiān)聽狀態(tài),等待遠(yuǎn)程用戶的連接。意味著這是一個使用TCP的協(xié)議服務(wù)器端程序,用于監(jiān)聽客戶機(jī)端的連接。例如:

TCP:21:0LISTENING

從上例可以看出,本地開啟端口21,通常為FTP服務(wù)進(jìn)程。因為IP地址顯示均為,表示該端口還處于監(jiān)聽狀態(tài),未建立連接。

●?ESTABLISHED狀態(tài),表示已建立通信連接,兩臺機(jī)器正在交換數(shù)據(jù),例如:

TCP0:21:3009ESTABLISHED說明主機(jī)0上開啟了FTP服務(wù),與主機(jī)上端口為3009的進(jìn)程建立了連接。當(dāng)主機(jī)53使用瀏覽器訪問某網(wǎng)站時,發(fā)現(xiàn)會有許多源IP地址和目的IP地址相同,并與處于ESTABLISHED狀態(tài)的套接字連接。這由網(wǎng)頁的構(gòu)成形式?jīng)Q定,網(wǎng)頁本身是純文本格式,它通過嵌入的方法鏈接引入各種格式的數(shù)據(jù),所以如果要查看完整的網(wǎng)頁,就需要將嵌入的所有數(shù)據(jù)都下載,所以圖片、flash動畫等都要單獨建立連接,如圖5-2所示。圖5-2當(dāng)訪問某網(wǎng)頁時建立的連接

5.2TCPSocket

由于TCP是面向連接的傳輸控制協(xié)議,因而在Java的包中,為實現(xiàn)TCPSocket提供了兩個基礎(chǔ)類,分別是Socket類和ServerSocket類。

●?Socket類:用于建立一個客戶機(jī)端通信對象,并向服務(wù)器端發(fā)起連接請求,在TCP連接成功后,通信雙方利用自有的Socket實例實現(xiàn)會話;

●?ServerSocket類:建立一個服務(wù)器端對象,專門用于監(jiān)聽客戶機(jī)端的連接請求,其通過accept()方法實現(xiàn)與客戶端的連接,完成TCP連接的三次握手。5.2.1Socket類

Socket類是TCPSocket中重要的類。該類有兩個作用:其一是作為客戶機(jī)端向指定的服務(wù)器發(fā)起連接請求,其二是在服務(wù)器端生成一個與客戶機(jī)端對等的通信實體,實現(xiàn)一對一的通信功能。其類定義如圖5-3所示。圖5-3Socket類的定義其常用構(gòu)造方法:

●?protectedSocket()throwsIOException,建立一個默認(rèn)的TCP客戶端套接字;

●?publicSocket(InetAddressaddr,intport)throwsIOException,向指定InetAddress的目標(biāo)服務(wù)器的端口port發(fā)起連接請求;

●?publicSocket(Stringhost,intport)throwsIOException,向指定名稱的目標(biāo)服務(wù)器的端口port發(fā)起連接請求。

Socket構(gòu)造方法的含義是,向某指定主機(jī)的指定端口發(fā)出連接請求,例如:

Socketsc1=newSocket("",80);//向主機(jī)上的標(biāo)識為80的服務(wù)進(jìn)程發(fā)起連接請求。

Socketsc2=newSocket(“”,80);//向主機(jī)上的標(biāo)識為80的服務(wù)進(jìn)程發(fā)起連接請求。

Socketsc3=newSocket(InetAddress.getByName(“”),80);參數(shù)使用了InetAddress對象,向目標(biāo)的80端口發(fā)起連接請求。

實際上,上面三個連接請求都是實現(xiàn)了向相同的Web服務(wù)器發(fā)起連接請求的功能,只不過是參數(shù)的形式不同而已。

Socket類常用的方法有:

●?publicvoidclose(),關(guān)閉當(dāng)前套接字;

●?intgetPort(),獲得對方Socket端口號;

●?intgetLocalPort(),獲得本地Socket端口號;

●?InetAddressgetInetAddress(),獲得對方InetAddress對象;

●?InetAddressgetLocalAddress(),獲得本地InetAddress對象;

●?InputStreamgetInputStream(), 獲得輸入流對象;

●?OutputStreamgetOutputStream(),獲得輸出流對象。代碼注釋如下:

①第1~2行在網(wǎng)絡(luò)編程時都需要引用java.io和類庫包;

②第5~6行設(shè)定要訪問的主機(jī)名稱為,端口為80;

③第7行聲明客戶端套接字變量cs;

④第9行向預(yù)先設(shè)定好的主機(jī)上的端口發(fā)起連接請求,如果連接成功的話則對客戶端套接字cs進(jìn)行賦值;

⑤第11~12行獲得本次連接套接字信息。

運行結(jié)果如圖5-4所示。圖5-4Socket常用方法演示代碼注釋如下:

①第6行設(shè)定目標(biāo)計算機(jī)名稱;

②第7行設(shè)定端口掃描范圍,應(yīng)在0~65?535之間。

③第8~16行嘗試連接指定主機(jī)的指定端口,并給出提示信息。

由于在測試遠(yuǎn)程主機(jī)端口時,等待應(yīng)答的時間可能會比較長,可以縮小探測端口的范圍。也可以將hostName設(shè)置為localhost或臨近的主機(jī)。運行結(jié)果如圖5-5所示。

當(dāng)利用Socket實現(xiàn)通信時,在實現(xiàn)與服務(wù)器連接后,客戶機(jī)端套接字上分別獲得輸入與輸出流,并且通過相應(yīng)方法從網(wǎng)絡(luò)獲取數(shù)據(jù)和向網(wǎng)絡(luò)發(fā)送數(shù)據(jù)。圖5-5測試主機(jī)的端口開放情況

代碼注釋如下:

①第6~7行分別聲明了輸入和輸出流對象;

②第9行向指定服務(wù)器localhost的80端口發(fā)起連接請求,如果連接成功則給客戶端套接字cs復(fù)制;

③第10~11行在套接字cs上通過getInputStream()和getOutputStream()方法分別獲得輸入和輸出流;

④第19~21行要求客戶端通過鍵盤輸入一個用戶名;

⑤第22~28行實現(xiàn)客戶端與服務(wù)器的通信;

⑥第22行定義了用于接收和發(fā)送數(shù)據(jù)的字符串變量fromServer和fromUser;

⑦第23行通過in.readUTF()從網(wǎng)絡(luò)接收數(shù)據(jù);

⑧第25行判斷收到的字符是否為“bye”,如果是則退出循環(huán)結(jié)束程序;⑨第27行從本地鍵盤輸入信息;

⑩第28行通過os.writeUTF()實現(xiàn)向網(wǎng)絡(luò)發(fā)送數(shù)據(jù);

??第29行通過調(diào)用os.flush()將存儲在本地發(fā)送緩存的數(shù)據(jù)立即向網(wǎng)絡(luò)發(fā)送,保證消息的實時性;

??第31~34行關(guān)閉流和套接字,釋放資源。

該代碼與例5-4配合執(zhí)行,運行結(jié)果如圖5-6所示。圖5-6客戶機(jī)端顯示5.2.2ServerSocket類

ServerSocket類用于在TCP傳輸?shù)姆?wù)器端建立一個監(jiān)聽端口,監(jiān)聽本地服務(wù)器是否接收到客戶機(jī)端的連接請求。當(dāng)接收到客戶機(jī)端連接請求,采用accept()方法確認(rèn)連接,并在本地返回一個Socket對象,利用該Socket對象與客戶機(jī)端Socket實現(xiàn)建立通信連接。其類定義如圖5-7所示。圖5-7ServerSocket類的定義其常用構(gòu)造方法:

●?ServerSocket()throwsIOException,建立一個服務(wù)器端標(biāo)識;

●?ServerSocket(intport)throwsIOException,在指定的端口建立一個服務(wù)器端標(biāo)識。

其端口取值范圍在0~65535之間,當(dāng)取值為0,表示使用本地任何空閑端口建立監(jiān)聽,監(jiān)聽本地某個指定的端口,例如:

ServerSocketss0=newServerSocket(80);//監(jiān)聽TCP80端口是否有連接請求

ServerSocketss1=newServerSocket(0);//監(jiān)聽某一空閑端口是否有連接請求

ServerSocket常用的方法有:

●?publicSocketaccept(),服務(wù)器接收客戶機(jī)端連接請求;

●?intgetLocalPort(),當(dāng)使用ServerSocket(0)構(gòu)造對象時,可獲得自動分配得到的監(jiān)聽端口號;●?publicvoidclose(),停止監(jiān)聽指定端口,關(guān)閉ServerSocket套接字。

由于TCP是面向連接的協(xié)議,提供可靠的通信服務(wù),因而經(jīng)常被用于文件傳輸?shù)扔锌煽啃砸蟮膱鼍爸小.?dāng)使用Java進(jìn)行TCP通信編程時,首先由服務(wù)器端利用ServerSocket開啟服務(wù)端口等待客戶機(jī)端的連接請求。其次,由客戶機(jī)端的Socket發(fā)起連接請求,服務(wù)器端使用accept()方法接收客戶機(jī)端,生成與客戶機(jī)端對應(yīng)的Socket,完成TCP連接建立。接下來服務(wù)器和客戶機(jī)端分別獲得對應(yīng)的輸入/輸出流,即可進(jìn)行通信。最后,通信結(jié)束分別關(guān)閉兩端的數(shù)據(jù)流和套接字,釋放系統(tǒng)資源。

圖5-8所示為TCPSocket通信的流程。圖5-8TCPSocket通信的流程

代碼注釋如下:

①第5~12行啟動監(jiān)聽本地的8080端口;

②第13~19行當(dāng)收到客戶端連接請求,通過accept()實現(xiàn)與客戶端的連接,并生成對應(yīng)的套接字cst;

③第20~21行在套接字cst上獲得輸入和輸出流;

④第24~35行實現(xiàn)與客戶端的通信,直至輸入“bye”為止。

該例程的運行結(jié)果與例5-3配合執(zhí)行,將實現(xiàn)一問一答式通信。運行結(jié)果如圖5-9所示。圖5-9服務(wù)器端顯示

5.3多?線?程?操?作

5.3.1多線程的概念

在上一節(jié)的例子中,實現(xiàn)的是通信最基本的形式“點到點(PointtoPoint,P2P)”通信,其特點是只有2人參與,進(jìn)行一問一答形式的信息交互。如果要實現(xiàn)多于2人參與的互動會話聊天室,在軟件設(shè)計時需要考慮如何接受多個參與者的申請,加入到同一個會話場景。

通常,在基于TCP的網(wǎng)絡(luò)編程中采用按照多線程的解決方案,以不同線程來與不同的用戶建立Socket連接,分別進(jìn)行通信。這樣的解決方案可以很容易在生活中發(fā)現(xiàn),例如火車票銷售系統(tǒng)、銀行存取系統(tǒng)或者是自來水供應(yīng)系統(tǒng)均能為多個客戶同時提供服務(wù)。在計算機(jī)中被執(zhí)行的程序稱為“進(jìn)程(Process)”,它是在計算機(jī)中依次執(zhí)行的指令,獨立占有系統(tǒng)資源,代表主動對象。線程(Thread)指進(jìn)程概念中的程序代碼的執(zhí)行位置。線程是屬于進(jìn)程的,一個進(jìn)程往往存在多個相似的線程。另一種更加形象的比喻是“線程是程序中的一條執(zhí)行路徑”,則多線程表示程序中包含多條執(zhí)行路徑。當(dāng)多個線程同時使用同一資源的時候,將會產(chǎn)生沖突。

【例5-5】

實現(xiàn)一組數(shù)1~30的累加,共啟用3個線程,每個線程都是從該數(shù)據(jù)集合中取10個數(shù)分別累加,最后將各線程的和再累加在一起。

代碼注釋如下:

①第1行因為要實現(xiàn)數(shù)字1~30的累加,所以定義一個共享資源類;

②第2行成員變量count為共享資源,為了避免外部直接引用,使用了private修飾符;

③第3~6行定義count的自增方法為?+1,并且通過synchronized聲明該方法在某個時刻只能被一個線程所調(diào)用,即排他行;

④第8~31行定義實現(xiàn)累加的線程;

⑤第34行定義計數(shù)器對象;⑥第35~40行定義三個累加的線程對象,并將這些對象作為參數(shù)傳遞為Thread類對象;

⑦第41~43行通過start()啟動累加線程;

⑧第44行通過join()將這些子線程加入到主線程中,保證當(dāng)子線程結(jié)束后,主線程才能結(jié)束;

⑨第45行輸出累加結(jié)果。

運行結(jié)果如圖5-10所示。

該例在第9章遠(yuǎn)程方法接口修改為分布式累加。圖5-10多線程累計結(jié)果5.3.2Java的多線程

Java中為用戶自定義線程類提供了兩種方法,分別是:

●?繼承Thread類,例如:

publicclassmyThreadextendsThread{}

●?實現(xiàn)Runnable接口,例如:

publicclassmyThreadimplmentsRunnable{}

這兩種方法都需要調(diào)用run()方法使線程運行。所以,自定義線程時必須覆蓋run()方法。由于Java的單繼承特性,通常建議在自定義線程類時采用Runnable接口。

Thread類提供了七種重載的構(gòu)造方法來實現(xiàn)線程類的實例化,分別是:●?publicThread(),默認(rèn)的構(gòu)造方法;

●?publicThread(Stringname),指定了線程名稱的構(gòu)造方法;

●?publicThread(Runnabletarget),帶有Runnable參數(shù)的構(gòu)造方法;

●?publicThread(Runnabletarget,Stringname),有Runnable參數(shù)和名稱的構(gòu)造方法;

●?publicThread(ThreadGroupgroup,Stringname),帶有線程組名和線程名的構(gòu)造方法;

●?publicThread(ThreadGroupgroup,Runnabletarget),帶有線程組名和Runnable參數(shù)的構(gòu)造方法; ●?publicThread(ThreadGroupgroup,Runnabletaget,Stringname)帶有線程組名和Runnable參數(shù),以及設(shè)定了線程名的構(gòu)造方法;

在利用Thread實現(xiàn)多線程時,需要先自定義線程類,然后聲明線程實例對象,最后調(diào)用start()使線程運行。在利用Runnable實現(xiàn)多線程時,不能直接創(chuàng)建線程類,必須先聲明一個Runnable實例對象,再將該實例傳遞給Thread類,才能調(diào)用start()使線程運行。代碼注釋如下:

①第2~7行與例5~6中的相同;

②第9~10行先聲明一個Runnable對象,再將該對象帶入Thread構(gòu)造方法;

③第11行通過start()啟動線程。

當(dāng)多個線程同時訪問一個資源的時候,就會出現(xiàn)系統(tǒng)運行異常,類似于數(shù)據(jù)庫操作中的臟讀和臟寫,所以引入線程同步的概念來避免它。同步的基本思想是避免多個線程訪問同一資源,可以通過“鎖”的形式實現(xiàn)。Java同步機(jī)制的作用就是力圖避免對“對象”訪問的沖突。為此,提供了一種信號量monitor來控制訪問對象的同步,使用關(guān)鍵字synchronized來修飾方法或者程序段,實現(xiàn)信號量的控制。Synchronized既可以用來鎖完整的成員方法,也可以用來鎖方法中某個程序段。5.3.3多線程與TCPSocket

聊天室(chatroom)是一個典型的多線程通信應(yīng)用程序。如果是基于TCP協(xié)議的通信,則服務(wù)器端必須利用多線程與每個客戶機(jī)端進(jìn)行單獨的連接,并采用線性表或鏈表保存每個客戶機(jī)端的Socket信息,然后由服務(wù)器以逐次轉(zhuǎn)發(fā)消息形式,實現(xiàn)消息的發(fā)布。如果是基于UDP通信,則可以選擇與TCP相類似的方法,也可以使用D類IP多播地址進(jìn)行群發(fā)信息。

在TCP中,首先服務(wù)器開啟指定的端口,用于監(jiān)聽客戶機(jī)端的連接請求??蛻魴C(jī)端發(fā)起連接請求,服務(wù)器端通過accept()接收,生成一個單獨的線程與每一個客戶機(jī)端進(jìn)行獨立的通信,如圖5-11所示。圖5-11基于TCP的多線程通信在程序設(shè)計時,可保持在客戶機(jī)端程序(例5-4)不改變的情況,在原單線程的服務(wù)器(例5-4)上改進(jìn),增加以下部分功能:

(1)設(shè)立主程序線程;

(2)增加while循環(huán),接受客戶機(jī)端的連接請求;

(3)設(shè)立對應(yīng)于客戶機(jī)端的對話線程;

(4)創(chuàng)建線程對象,并啟動該線程。

代碼注釋如下:

①第3行聲明主程序為線程;

②第5~13行在構(gòu)造方法中實現(xiàn)監(jiān)聽本地的指定端口;

③第16~20行采用while循環(huán)的方法無限地接收客戶端的連接請求;

④第25~53行定義客戶端的通信線程類,該類實現(xiàn)了Runnable接口;

⑤第54~58行啟動主程序。

例5-8是一個簡化的多線程服務(wù)器端程序,實際上真實環(huán)境下需要為服務(wù)器主程序、與客戶端連接、接收客戶端消息、給客戶端發(fā)送消息等設(shè)置線程。5.3.4多客戶端信息存儲

在上節(jié)中僅討論了如何使用多線程連接多個客戶機(jī)端。而實際上要滿足一個簡單聊天室的功能,還需要考慮以下重要的內(nèi)容:

●?如何保存客戶機(jī)端的信息,例如,客戶機(jī)端的Socket信息等,當(dāng)服務(wù)器端收到客戶機(jī)端發(fā)送的消息后,如何將消息向聊天室里所有用戶的分發(fā);

●?如何設(shè)計消息的格式,即在聊天室中發(fā)送的消息應(yīng)該包含哪些內(nèi)容,例如,信息的發(fā)送者、接收者目的地,以及內(nèi)容等;圖5-12Java中的線性表和鏈表類通常,為了保存所有連接到服務(wù)器的客戶機(jī)端Socket信息,可以采用Java所提供的線性表Collection或鏈表Map等數(shù)據(jù)結(jié)構(gòu),這些結(jié)構(gòu)保存在java.util類庫中,如圖5-12所示。其中,Java.util.Vector提供了向量(Vector)類以實現(xiàn)動態(tài)數(shù)組的功能,在多線程編程時經(jīng)常被使用。每個Vector實例都有一個容量(Capacity),用于存儲元素的數(shù)組,這個容量可隨著不斷添加新元素而自動增加。

Vector的構(gòu)造方法有:

●?Vector();//構(gòu)造一個空的實例對象

●?Vector(int

initialCapacity);//構(gòu)造一個初始有一個向量的實例對象

●?Vector(int

initialCapacity,int

capacityIncrement);//構(gòu)造一個初始有一個向量,并且每次遞增一個的實例對象例如:

VectoruserList=newVector();

其常用方法有:

Vector.add(element);

//添加一個元素

VectoruserList.remove(socket);

//移除一個指定元素

Vector.size();

//獲取Vector中元素個數(shù)

在例5-8基礎(chǔ)上進(jìn)行修改,第一,需要在myServer類中聲明一個Vector對象,如下:第三,修改客戶通信線類,這時將服務(wù)器端僅作為消息的轉(zhuǎn)發(fā)者,不允許通過鍵盤輸入與客戶機(jī)端對話:第四,為了客戶機(jī)端能及時地收到服務(wù)器轉(zhuǎn)發(fā)過來的消息,需要為客戶機(jī)端的接收和發(fā)送數(shù)據(jù)流分別設(shè)置2個線程。

【例5-9】多線程的客戶機(jī)端代碼。

代碼注釋如下:

①第3行聲明客戶端為線程;

②第4~9行聲明成員變量;

③第14~28行聲明客戶端線程的啟動方法;

④第16行連接指定的服務(wù)器端;

⑤第23行啟動消息的接收線程;

⑥第24行啟動消息的發(fā)送線程;

⑦第29~48行聲明內(nèi)部接收線

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論