《Java程序設(shè)計(jì)教程》課件第十五章:網(wǎng)絡(luò)編程_第1頁(yè)
《Java程序設(shè)計(jì)教程》課件第十五章:網(wǎng)絡(luò)編程_第2頁(yè)
《Java程序設(shè)計(jì)教程》課件第十五章:網(wǎng)絡(luò)編程_第3頁(yè)
《Java程序設(shè)計(jì)教程》課件第十五章:網(wǎng)絡(luò)編程_第4頁(yè)
《Java程序設(shè)計(jì)教程》課件第十五章:網(wǎng)絡(luò)編程_第5頁(yè)
已閱讀5頁(yè),還剩44頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

本章學(xué)習(xí)目標(biāo):●了解Java網(wǎng)絡(luò)相關(guān)的API●掌握Socket類及其方法的使用●掌握ServerSocket類的使用第十五章網(wǎng)絡(luò)編程第1節(jié)partJava網(wǎng)絡(luò)API

最初,Java就是作為網(wǎng)絡(luò)編程語(yǔ)言而出現(xiàn)的,其本身就對(duì)網(wǎng)絡(luò)通信提供了支持,允許使用網(wǎng)絡(luò)上的各種資源和數(shù)據(jù),與服務(wù)器建立各種傳輸通道,實(shí)現(xiàn)數(shù)據(jù)的傳輸,使網(wǎng)絡(luò)編程實(shí)現(xiàn)起來(lái)變得簡(jiǎn)單。Java中有關(guān)網(wǎng)絡(luò)方面的功能都定義在包中,該包下的URL和URLConnection等類提供了以程序的方式來(lái)訪問Web服務(wù),而URLDecoder和URLEncoder則提供了普通字符串和application/x-www-form-urlencodeMIME字符串相互轉(zhuǎn)換的靜態(tài)方法。Java網(wǎng)絡(luò)API本節(jié)概述Java提供InetAddress類來(lái)封裝IP地址或域名,InetAddress類有兩個(gè)子類:Inet4Address類和Inet6Address類,分別用于封裝4個(gè)字節(jié)的IP地址和6個(gè)字節(jié)的IP地址。InetAddress內(nèi)部對(duì)地址數(shù)字進(jìn)行隱藏,用戶不需要了解實(shí)現(xiàn)地址的細(xì)節(jié),只需了解如何調(diào)用相應(yīng)的方法即可。InetAddress類無(wú)構(gòu)造方法,因此不能直接創(chuàng)建其對(duì)象,而是通過(guò)該類的靜態(tài)方法創(chuàng)建一個(gè)InetAddress對(duì)象或InetAddress數(shù)組。InetAddress類常用方法如表15-1所示。表15-1InetAddress類常用方法15.1.1InetAddress類InetAddress類下述案例示例了InetAddress類的使用,代碼如下所示?!敬a15.1】InetAddressExample.javapackagecom;importjava.io.IOException;import.InetAddress;import.UnknownHostException;publicclassInetAddressExample{ publicstaticvoidmain(String[]args){ try{ //獲取本機(jī)地址信息 InetAddresslocalIp=InetAddress.getLocalHost(); System.out.println("localIp.getCanonicalHostName()=" +localIp.getCanonicalHostName()); System.out.println("localIp.getHostAddress()=" +localIp.getHostAddress()); System.out.println("localIp.getHostName()=" +localIp.getHostName()); System.out.println("localIp.toString()=" +localIp.toString()); System.out.println("localIp.isReachable(5000)=“+localIp.isReachable(5000)); System.out.println("--------------");InetAddress類15.1.1 //獲取指定域名地址信息 InetAddressbaiduIp=InetAddress.getByName(""); System.out.println("baiduIp.getCanonicalHostName()=" +baiduIp.getCanonicalHostName()); System.out.println("baiduIp.getHostAddress()=" +baiduIp.getHostAddress()); System.out.println("baiduIp.getHostName()=" +baiduIp.getHostName()); System.out.println("baiduIp.toString()=" +baiduIp.toString()); System.out.println("baiduIp.isReachable(5000)=" +baiduIp.isReachable(5000)); System.out.println("-----------------"); //獲取指定原始IP地址信息 InetAddressip=InetAddress.getByAddress(newbyte[]{127,0,0,1}); //InetAddressip=InetAddress.getByName(""); System.out.println("ip.getCanonicalHostName()=“+ip.getCanonicalHostName()); System.out.println("ip.getHostAddress()=“+ip.getHostAddress()); System.out.println("ip.getHostName()=“+ip.getHostName()); System.out.println("ip.toString()="+ ip.toString());InetAddress類15.1.1 System.out.println("ip.isReachable(5000)=“+ip.isReachable(5000)); }catch(UnknownHostExceptione){ e.printStackTrace(); }catch(Exceptione){ e.printStackTrace(); } }}InetAddress類

上述代碼分別獲取本機(jī)、指定域名以及指定IP地址的InetAddress對(duì)象。其中,調(diào)用getLocalHost()可以獲取本機(jī)InetAddress對(duì)象;調(diào)用getByName()可以獲取指定域名的InetAddress對(duì)象;調(diào)用getByAddress()可以獲取指定IP地址的InetAddress對(duì)象,該方法的參數(shù)使用字節(jié)數(shù)組存放IP地址。也可以直接通過(guò)getByName()獲取指定IP地址的InetAddress對(duì)象,此時(shí),IP地址作為字符串即可。15.1.1程序運(yùn)行結(jié)果如下所示:localIp.getCanonicalHostName()=01localIp.getHostAddress()=01localIp.getHostName()=shouchao-PClocalIp.toString()=shouchao-PC/01localIp.isReachable(5000)=true--------------baiduIp.getCanonicalHostName()=08baiduIp.getHostAddress()=08baiduIp.getHostName()=baiduIp.toString()=/08baiduIp.isReachable(5000)=false-----------------ip.getCanonicalHostName()=ip.getHostAddress()=ip.getHostName()=ip.toString()=/ip.isReachable(5000)=trueInetAddress類

需要注意的是:在獲得Internet上的域名所對(duì)應(yīng)的地址信息時(shí),需保證運(yùn)行環(huán)境能訪問Internet,否則將拋出UnknownHostException異常。15.1.1URL(UniformResourceLocator,統(tǒng)一資源定位器)表示互聯(lián)網(wǎng)上某一資源的地址。資源可以是簡(jiǎn)單的文件或目錄,也可以是對(duì)更為復(fù)雜對(duì)象的引用,例如對(duì)數(shù)據(jù)庫(kù)或搜索引擎的查詢。URL是最為直觀的一種網(wǎng)絡(luò)定位方法,符合人們的語(yǔ)言習(xí)慣,且容易記憶。在通常情況下,URL可以由協(xié)議名、主機(jī)、端口和資源四個(gè)部分組成,其語(yǔ)法格式如下所示:protocol://host:port/resourceName

其中:

●protocol是協(xié)議名,指明獲取資源所使用的傳輸協(xié)議,例如http、ftp等,并使用冒號(hào)“:”與其他部分進(jìn)行隔離;

●host是主機(jī)名,指定獲取資源的域名,此部分由左邊的雙斜線“//”和右邊的單斜線“/”或可選冒號(hào)“:”限制;

●port是端口,指定服務(wù)的端口號(hào),是一個(gè)可選參數(shù),由主機(jī)名左邊的冒號(hào)“:”和右邊的斜線“/”限制;

●resourceName是資源名,指定訪問的文件名或目錄。

例如:URL地址

:8080/student/index.jsp15.1.2URL類URL類

為了方便處理,Java將URL封裝成URL類,通過(guò)URL對(duì)象記錄下完整的URL信息。URL類常用方法及功能如表15-2所示。15.1.2URL類下述案例示例了根據(jù)指定的路徑構(gòu)造URL對(duì)象,并獲取當(dāng)前URL對(duì)象的相關(guān)屬性。代碼如下所示?!敬a15.2】URLExample.javapackagecom;import.MalformedURLException;import.URL;publicclassURLExample{publicstaticvoidmain(String[]args){ try{ URLmybook=newURL(":8080/student/index.jsp"); System.out.println("協(xié)議protocol="+mybook.getProtocol()); System.out.println("主機(jī)host="+mybook.getHost()); System.out.println("端口port="+mybook.getPort()); System.out.println("文件filename="+mybook.getFile()); System.out.println("錨ref="+mybook.getRef()); System.out.println("查詢信息query="+mybook.getQuery()); System.out.println("路徑path="+mybook.getPath()); }catch(MalformedURLExceptione){ e.printStackTrace(); }}}程序運(yùn)行結(jié)果如下所示:協(xié)議protocol=http主機(jī)host=:8080端口port=-1文件filename=/student/index.jsp錨ref=null查詢信息query=null路徑path=/student/index.jsp15.1.2URL類URLConnection代表與URL指定的數(shù)據(jù)源的動(dòng)態(tài)連接,該類提供一些比URL類更強(qiáng)大的服務(wù)器交互控制的方法,允許使用POST或PUT和其他HTTP請(qǐng)求方法將數(shù)據(jù)送回服務(wù)器。URLConnection是一個(gè)抽象類,其常用方法如表15-3所示。15.1.3URLConnection類URLConnection類下述案例示例了使用URLConnection類讀取網(wǎng)絡(luò)資源信息并打印,代碼如下所示?!敬a15.3】URLConnectionExample.javapackagecom;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;import.MalformedURLException;import.URL;import.URLConnection;publicclassURLConnectionExample{publicstaticvoidmain(String[]args){try{ //構(gòu)建一URL對(duì)象 URLmybook=newURL("/"); //由URL對(duì)象獲取URLConnection對(duì)象 URLConnectionurlConn=mybook.openConnection();//設(shè)置請(qǐng)求屬性,字符集是UTF-8 urlConn.setRequestProperty("Charset","GBK"); //由URLConnection獲取輸入流,并構(gòu)造BufferedReader對(duì)象 BufferedReaderbr=newBufferedReader(newInputStreamReader(urlConn.getInputStream()));15.1.3URLConnection類 StringinputLine; //循環(huán)讀取并打印數(shù)據(jù) while((inputLine=br.readLine())!=null){ System.out.println(inputLine); } //關(guān)閉輸入流 br.close(); }catch(MalformedURLExceptione){ e.printStackTrace(); }catch(IOExceptione){ e.printStackTrace(); }}}

上述代碼的運(yùn)行結(jié)果是輸出指定網(wǎng)頁(yè)頁(yè)面的源代碼,此處不顯示輸出效果,讀者可以自己調(diào)試程序查看。15.1.3URLConnection類

當(dāng)URL地址中包含非西歐字符時(shí),系統(tǒng)會(huì)將這些非西歐字符轉(zhuǎn)換成特殊編碼(如“%XX”格式),此種編碼稱為application/x-www-form-urlencodedMIME。在編程過(guò)程中如果涉及到普通字符串和application/x-www-form-urlencodedMIME字符串之間相互轉(zhuǎn)換時(shí),就需要使用URLDecoder和URLEncoder兩個(gè)工具類。

●URLDecoder工具類提供了一個(gè)decode(Strings,Stringenc)靜態(tài)方法,該方法將application/x-www-form-urlencodedMIME字符串轉(zhuǎn)換成普通字符串;

●URLEncoder工具類提供了一個(gè)encode(Strings,Stringenc)靜態(tài)方法,該方法與decode()方法正好相反,能夠?qū)⑵胀ǖ淖址D(zhuǎn)換成application/x-www-form-urlencodedMIME字符串。15.1.4URLDecoder和URLEncoder類URLDecoder和URLEcoder類下述案例示例了URLDecoder和URLEncoder兩個(gè)工具類的使用,代碼如下所示?!敬a15.4】URLDecoderExample.javapackagecom;importjava.io.UnsupportedEncodingException;import.URLDecoder;import.URLEncoder;publicclassURLDecoderExample{ publicstaticvoidmain(String[]args){ try{ //將普通字符串轉(zhuǎn)換成application/x-www-form-urlencoded字符串 StringurlStr=URLEncoder.encode("面向?qū)ο蟪绦蛟O(shè)計(jì)Java","GBK"); System.out.println(urlStr); //將application/x-www-form-urlencoded字符串轉(zhuǎn)換成普通字符串 StringkeyWord=URLDecoder.decode( "%C3%E6%CF%F2%B6%D4%CF%F3%B3%CC%D0%F2%C9%E8%BC%C6Java","GBK"); System.out.println(keyWord); }catch(UnsupportedEncodingExceptione){ e.printStackTrace(); } }}程序運(yùn)行結(jié)果如下:%C3%E6%CF%F2%B6%D4%CF%F3%B3%CC%D0%F2%C9%E8%BC%C6Java面向?qū)ο蟪绦蛟O(shè)計(jì)Java15.1.4URLDecoder和URLEncoder類第2節(jié)part基于TCP的網(wǎng)路編程TCP/IP通信協(xié)議是一種可靠的、雙向的、持續(xù)的、點(diǎn)對(duì)點(diǎn)的網(wǎng)絡(luò)協(xié)議。使用TCP/IP協(xié)議進(jìn)行通信時(shí),會(huì)在通信的兩端各建立一個(gè)Socket(套接字),從而在通信的兩端之間形成網(wǎng)絡(luò)虛擬鏈路,其通信原理如圖15.1所示?;赥CP的網(wǎng)路編程本節(jié)概述Java對(duì)基于TCP的網(wǎng)絡(luò)通信提供了封裝,使用Socket對(duì)象封裝了兩端的通信端口。Socket對(duì)象屏蔽了網(wǎng)絡(luò)的底層細(xì)節(jié),例如媒體類型、信息包的大小、網(wǎng)絡(luò)地址、信息的重發(fā)等。Socket允許應(yīng)用程序?qū)⒕W(wǎng)絡(luò)連接當(dāng)成一個(gè)IO流,既可以向流中寫數(shù)據(jù),也可以從流中讀取數(shù)據(jù)。一個(gè)Socket對(duì)象可以用來(lái)建立Java的IO系統(tǒng)到Internet上的任何機(jī)器(包括本機(jī))的程序連接。

包中提供了網(wǎng)絡(luò)編程所需的類,其中基于TCP協(xié)議的網(wǎng)絡(luò)編程主要使用下面兩種Socket:

●ServerSocket:是服務(wù)器套接字,用于監(jiān)聽并接收來(lái)自客戶端的Socket連接;

●Socket:是客戶端套接字,用于實(shí)現(xiàn)兩臺(tái)計(jì)算機(jī)之間的通信?;赥CP的網(wǎng)路編程15.2.1Socket類

使用Socket套接字可以較為方便地在網(wǎng)絡(luò)上傳遞數(shù)據(jù),從而實(shí)現(xiàn)兩臺(tái)計(jì)算機(jī)之間的通信。通??蛻舳耸褂肧ocket來(lái)連接指定的服務(wù)器,Socket的兩個(gè)常用構(gòu)造方法如下:

●Socket(InetAddress|Stringhost,intport):創(chuàng)建連接到指定遠(yuǎn)程主機(jī)和端口號(hào)的Socket對(duì)象,該構(gòu)造方法沒有指定本地地址和本地端口號(hào),默認(rèn)使用本地主機(jī)IP地址和系統(tǒng)動(dòng)態(tài)分配的端口;

●Socket(InetAddress|Stringhost,intport,InetAddresslocalAddr,intlocalPort):創(chuàng)建連接到指定遠(yuǎn)程主機(jī)和端口號(hào)的Socket對(duì)象,并指定本地IP地址和本地端口號(hào),適用于本地主機(jī)有多個(gè)IP地址的情況。

需要注意的是:上述兩個(gè)Socket構(gòu)造方法都聲明拋出IOException異常,因此在創(chuàng)建Socket對(duì)象必須捕獲或拋出異常。端口號(hào)建議采用注冊(cè)端口(范圍是1024~49151之間的數(shù)),通常應(yīng)用程序使用該范圍內(nèi)的端口,以防止發(fā)生沖突。Socket類

例如:創(chuàng)建Socket對(duì)象try{Sockets=newSocket("28",9999);...//Socket通信}catch(IOExceptione){e.printStackTrace();}

除了構(gòu)造方法,Socket類常用的其他方法如表15-4所示。15.2.1Socket類

通常使用Socket進(jìn)行網(wǎng)絡(luò)通信的具體步驟如下:

①根據(jù)指定IP地址和端口號(hào)創(chuàng)建一個(gè)Socket對(duì)象;

②調(diào)用getInputStream()方法或getOutputStream()方法打開連接到Socket的輸入/輸出流;

③客戶端與服務(wù)器根據(jù)協(xié)議進(jìn)行交互,直到關(guān)閉連接;

④關(guān)閉客戶端的Socket。

下述案例示例了創(chuàng)建客戶端Socket的過(guò)程,代碼如下所示。15.2.1Socket類【代碼15.5】ClientSocketExample.javapackagecom;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintStream;import.Socket;import.UnknownHostException;publicclassClientSocketExample{publicstaticvoidmain(String[]args){try{ //創(chuàng)建連接到本機(jī)、端口為9999的Socket對(duì)象 Socketsocket=newSocket("",9999); //將Socket對(duì)應(yīng)的輸出流包裝成PrintStream PrintStreamps=newPrintStream(socket.getOutputStream()); //往服務(wù)器發(fā)送信息 ps.println("我喜歡Java"); ps.flush(); //將Socket對(duì)應(yīng)的輸入流包裝成BufferedReader BufferedReaderbr=newBufferedReader(newInputStreamReader(socket.getInputStream()));15.2.1Socket類 //讀服務(wù)器返回的信息并顯示 Stringline=br.readLine(); System.out.println("來(lái)自服務(wù)器的數(shù)據(jù):"+line); //關(guān)閉 br.close(); ps.close(); socket.close(); }catch(UnknownHostExceptione){ e.printStackTrace(); }catch(IOExceptione){ e.printStackTrace(); }}}

上述代碼先創(chuàng)建了一個(gè)連接到本機(jī)、端口為9999的Socket對(duì)象;再使用getOutputStream()獲取Socket對(duì)象的輸出流,用于往服務(wù)器發(fā)送信息;然后使用getInputStream()獲取Socket對(duì)象的輸入流,讀取服務(wù)器返回的數(shù)據(jù);最后關(guān)閉輸入/輸出流和Socket連接,釋放所有的資源。15.2.1Socket類15.2.2ServletSocket類ServerSocket是服務(wù)器套接字,運(yùn)行在服務(wù)器端,通過(guò)指定端口主動(dòng)監(jiān)聽來(lái)自客戶端的Socket連接。當(dāng)客戶端發(fā)送Socket請(qǐng)求并與服務(wù)器端建立連接時(shí),服務(wù)器將驗(yàn)證并接收客戶端的Socket,從而建立客戶端與服務(wù)器之間的網(wǎng)絡(luò)虛擬鏈路;一旦兩端的實(shí)體之間建立了虛擬鏈路,就可以相互傳送數(shù)據(jù)。ServerSocket類常用的構(gòu)造方法如下:

●ServerSocket(intport):根據(jù)指定端口來(lái)創(chuàng)建一個(gè)ServerSocket對(duì)象;

●ServerSocket(intport,intbacklog):創(chuàng)建一個(gè)ServerSocket對(duì)象,指定端口和連接隊(duì)列長(zhǎng)度,此時(shí)增加一個(gè)用來(lái)改變連接隊(duì)列長(zhǎng)度的參數(shù)backlog;

●ServerSocket(intport,intbacklog,InetAddresslocalAddr):創(chuàng)建一個(gè)ServerSocket對(duì)象,指定端口、連接隊(duì)列長(zhǎng)度和IP地址;當(dāng)機(jī)器擁有多個(gè)IP地址時(shí),才允許使用localAddr參數(shù)指定具體的IP地址。ServletSocket類

需要注意的是:ServerSocket類的構(gòu)造方法都聲明拋出IOException異常,因此在創(chuàng)建ServerSocket對(duì)象必須捕獲或拋出異常。另外,在選擇端口號(hào)時(shí),建議選擇注冊(cè)端口(范圍是1024~49151的數(shù)),通常應(yīng)用程序使用這個(gè)范圍內(nèi)的端口,以防止發(fā)生沖突。

下面幾行代碼示例了創(chuàng)建一個(gè)ServerSocket對(duì)象:try{ ServerSocketserver=newServerSocket(9999);}catch(IOExceptione){ e.printStackTrace();}ServerSocket類常用的其他方法如表15-5所示。15.2.2ServletSocket類通常使用ServerSocket進(jìn)行網(wǎng)絡(luò)通信的具體步驟如下:①根據(jù)指定的端口號(hào)來(lái)實(shí)例化一個(gè)ServerSocket對(duì)象;②調(diào)用ServerSocket對(duì)象的accept()方法接收客戶端發(fā)送的Socket對(duì)象;③調(diào)用Socket對(duì)象的getInputStream()/getOutputStream()方法來(lái)建立與客戶端進(jìn)行交互的IO流;④服務(wù)器與客戶端根據(jù)一定的協(xié)議交互,直到關(guān)閉連接;⑤關(guān)閉服務(wù)器端的Socket;⑥回到第2步,繼續(xù)監(jiān)聽下一次客戶端發(fā)送的Socket請(qǐng)求連接。下述案例示例了創(chuàng)建服務(wù)器端ServerSocket的過(guò)程,代碼如下所示。15.2.2ServletSocket類【15.6】ServerSocketExample.javapackagecom;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintStream;import.ServerSocket;import.Socket;publicclassServerSocketExampleextendsThread{ //聲明一個(gè)ServerSocket ServerSocketserver; //計(jì)數(shù) intnum=0; publicServerSocketExample(){ //創(chuàng)建ServerSocket,用于監(jiān)聽9999端口是否有客戶端的Socket try{ server=newServerSocket(9999); }catch(IOExceptione){ e.printStackTrace(); }15.2.2ServletSocket類 //啟動(dòng)當(dāng)前線程,即執(zhí)行run()方法 this.start(); System.out.println("服務(wù)器啟動(dòng)..."); } publicvoidrun(){ while(this.isAlive()){ try{ //接收客戶端的Socket Socketsocket=server.accept(); //將Socket對(duì)應(yīng)的輸入流包裝成BufferedReader BufferedReaderbr=newBufferedReader(newInputStreamReader( socket.getInputStream())); //讀客戶端發(fā)送的信息并顯示 Stringline=br.readLine(); System.out.println(line); //將Socket對(duì)應(yīng)的輸出流包裝成PrintStream PrintStreamps=newPrintStream(socket.getOutputStream()); //往客戶端發(fā)送信息 ps.println("您是第"+(++num)+"個(gè)訪問服務(wù)器的用戶!"); ps.flush();15.2.2ServletSocket類 //關(guān)閉 br.close(); ps.close(); socket.close(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } } publicstaticvoidmain(String[]args){ newServerSocketExample(); }}15.2.2ServletSocket類

上述代碼服務(wù)器端是一個(gè)多線程應(yīng)用程序,能為多個(gè)客戶提供服務(wù)。在ServerSocketExample()構(gòu)造方法中,先創(chuàng)建一個(gè)用于監(jiān)聽9999端口的ServerSocket對(duì)象,再調(diào)用this.start()方法啟動(dòng)線程。在線程的run()方法中,先調(diào)用ServerSocket對(duì)象的accept()方法來(lái)接收客戶端發(fā)送的Socket對(duì)象;再使用getInputStream()獲取Socket對(duì)象的輸入流,用于讀取客戶端發(fā)送的數(shù)據(jù)信息;然后使用getOutputStream()獲取Socket對(duì)象的輸出流,往客戶端發(fā)送信息;最后關(guān)閉輸入、輸出流和Socket,釋放所有資源。

前面編寫的客戶端程序ClientSocketExample與服務(wù)器端程序ServerSocketExample能夠形成網(wǎng)絡(luò)通信,運(yùn)行時(shí)先運(yùn)行服務(wù)器端ServerSocketExample應(yīng)用程序,服務(wù)器端先顯示如下提示:

服務(wù)器啟動(dòng)...

然后,運(yùn)行客戶端ClientSocketExample應(yīng)用程序,此時(shí)服務(wù)器端又會(huì)增加打印一條信息:

我喜歡Java

客戶端應(yīng)用程序會(huì)顯示:

來(lái)自服務(wù)器的數(shù)據(jù):您是第1個(gè)訪問服務(wù)器的用戶!15.2.2ServletSocket類

一般服務(wù)器和客戶端之間,使用Socket進(jìn)行基于C/S架構(gòu)的網(wǎng)絡(luò)通信,程序設(shè)計(jì)的過(guò)程如下:

①服務(wù)器端通過(guò)某個(gè)端口監(jiān)聽是否有客戶端發(fā)送Socket連接請(qǐng)求;

②客戶端向服務(wù)器端發(fā)出一個(gè)Socket連接請(qǐng)求;

③服務(wù)器端調(diào)用accept()接收客戶端Socket并建立連接;

④通過(guò)調(diào)用Socket對(duì)象的getInputStream()/getOutputStream()方法進(jìn)行IO流操作,服務(wù)器與客戶端之間進(jìn)行信息交互;

⑤關(guān)閉服務(wù)器端和客戶端的Socket。15.2.2ServletSocket類15.2.3聊天室

基于TCP網(wǎng)絡(luò)編程的典型應(yīng)用就是聊天室,下述內(nèi)容使用Socket和ServerSocket實(shí)現(xiàn)多人聊天的聊天室程序。聊天室程序是基于C/S架構(gòu),分客戶端代碼和服務(wù)器端代碼。其中,客戶端是一個(gè)窗口應(yīng)用程序,代碼如下。聊天室【代碼15.7】ChatClient.javapackagecom;importjava.awt.BorderLayout;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintWriter;import.Socket;import.UnknownHostException;importjavax.swing.*;//聊天室客戶端publicclassChatClientextendsJFrame{ Socketsocket; PrintWriterpWriter; BufferedReaderbReader; JPanelpanel; JScrollPanesPane; JTextAreatxtContent;15.2.3聊天室 JLabellblName,lblSend; JTextFieldtxtName,txtSend; JButtonbtnSend; publicChatClient(){ super("聊天室"); txtContent=newJTextArea(); //設(shè)置文本域只讀 txtContent.setEditable(false); sPane=newJScrollPane(txtContent); lblName=newJLabel("昵稱:"); txtName=newJTextField(5); lblSend=newJLabel("發(fā)言:"); txtSend=newJTextField(20); btnSend=newJButton("發(fā)送"); panel=newJPanel(); panel.add(lblName); panel.add(txtName); panel.add(lblSend); panel.add(txtSend); panel.add(btnSend);15.2.3聊天室 this.add(panel,BorderLayout.SOUTH); this.add(sPane); this.setSize(500,300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); try{ //創(chuàng)建一個(gè)套接字 socket=newSocket("",9999); //創(chuàng)建一個(gè)往套接字中寫數(shù)據(jù)的管道,即輸出流,給服務(wù)器發(fā)送信息 pWriter=newPrintWriter(socket.getOutputStream()); //創(chuàng)建一個(gè)從套接字讀數(shù)據(jù)的管道,即輸入流,讀服務(wù)器的返回信息 bReader=newBufferedReader( newInputStreamReader(socket.getInputStream())); }catch(UnknownHostExceptione){ e.printStackTrace(); }catch(IOExceptione){ e.printStackTrace(); } //注冊(cè)監(jiān)聽 btnSend.addActionListener(newActionListener(){ publicvoidactionPerformed(ActionEvente){15.2.3聊天室 //獲取用戶輸入的文本 StringstrName=txtName.getText(); StringstrMsg=txtSend.getText(); if(!strMsg.equals("")){ //通過(guò)輸出流將數(shù)據(jù)發(fā)送給服務(wù)器 pWriter.println(strName+"說(shuō):"+strMsg); pWriter.flush(); //清空文本框 txtSend.setText(""); } } }); //啟動(dòng)線程 newGetMsgFromServer().start(); } //接收服務(wù)器的返回信息的線程 classGetMsgFromServerextendsThread{ publicvoidrun(){ while(this.isAlive()){ try{15.2.3聊天室 StringstrMsg=bReader.readLine(); if(strMsg!=null){ //在文本域中顯示聊天信息 txtContent.append(strMsg+"\n"); } Thread.sleep(50); }catch(Exceptione){ e.printStackTrace(); } } } } publicstaticvoidmain(Stringargs[]){ //創(chuàng)建聊天室客戶端窗口實(shí)例,并顯示 newChatClient().setVisible(true); }}15.2.3聊天室

上述代碼在構(gòu)造方法中先創(chuàng)建客戶端圖形界面,并創(chuàng)建一個(gè)Socket對(duì)象連接服務(wù)器,然后獲取Socket對(duì)象的輸入流和輸出流,用于與服務(wù)器進(jìn)行信息交互,輸出流可以給服務(wù)器發(fā)送信息,輸入流可以讀取服務(wù)器的返回信息。再對(duì)“發(fā)送”按鈕添加監(jiān)聽事件處理,當(dāng)用戶單擊“發(fā)送”按鈕時(shí),將用戶在文本框中輸入的數(shù)據(jù)通過(guò)輸出流寫到Socket中,實(shí)現(xiàn)將信息發(fā)送給服務(wù)器。GetMsgFromServer是一個(gè)用于不斷循環(huán)接收服務(wù)器的返回信息的線程,只要接收到服務(wù)器的信息,就將該信息在窗口的文本域中顯示。注意在構(gòu)造方法的最后創(chuàng)建一個(gè)GetMsgFromServer線程實(shí)例并啟動(dòng)。

聊天室的服務(wù)器端代碼如下所示。15.2.3聊天室【代碼15.8】ChatServer.javapackagecom;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintWriter;import.ServerSocket;import.Socket;importjava.text.SimpleDateFormat;importjava.util.ArrayList;importjava.util.Date;importjava.util.LinkedList;//聊天室服務(wù)器端publicclassChatServer{ //聲明服務(wù)器端套接字ServerSocket ServerSocketserverSocket; //輸入流列表集合 ArrayList<BufferedReader>bReaders=newArrayList<BufferedReader>(); //輸出流列表集合 ArrayList<PrintWriter>pWriters=newArrayList<PrintWriter>();15.2.3聊天室 //聊天信息鏈表集合 LinkedList<String>msgList=newLinkedList<String>(); publicChatServer(){ try{ //創(chuàng)建服務(wù)器端套接字ServerSocket,在28888端口監(jiān)聽 serverSocket=newServerSocket(9999); }catch(IOExceptione){ e.printStackTrace(); } //創(chuàng)建接收客戶端Socket的線程實(shí)例,并啟動(dòng) newAcceptSocketThread().start(); //創(chuàng)建給客戶端發(fā)送信息的線程實(shí)例,并啟動(dòng) newSendMsgToClient().start(); System.out.println("服務(wù)器已啟動(dòng)..."); } //接收客戶端Socket套接字線程 classAcceptSocketThreadextendsThread{ publicvoidrun(){ while(this.isAlive()){ try{15.2.3聊天室 //接收一個(gè)客戶端Socket對(duì)象 Socketsocket=serverSocket.accept(); //建立該客戶端的通信管道 if(socket!=null){ //獲取Socket對(duì)象的輸入流 BufferedReaderbReader=newBufferedReader( newInputStreamReader(socket.getInputStream())); //將輸入流添加到輸入流列表集合中 bReaders.add(bReader); //開啟一個(gè)線程接收該客戶端的聊天信息 newGetMsgFromClient(bReader).start(); //獲取Socket對(duì)象的輸出流,并添加到輸入出流列表集合中 pWriters.add(newPrintWriter(socket.getOutputStream())); } }catch(IOExceptione){ e.printStackTrace(); } } } }15.2.3聊天室//接收客戶端的聊天信息的線程classGetMsgFromClientextendsThread{BufferedReaderbReade

溫馨提示

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

評(píng)論

0/150

提交評(píng)論