![《PHP》課件模塊九 網(wǎng)絡編程_第1頁](http://file4.renrendoc.com/view12/M05/23/01/wKhkGWZ8CQ6AW_nQAAGZ54Gh1w4037.jpg)
![《PHP》課件模塊九 網(wǎng)絡編程_第2頁](http://file4.renrendoc.com/view12/M05/23/01/wKhkGWZ8CQ6AW_nQAAGZ54Gh1w40372.jpg)
![《PHP》課件模塊九 網(wǎng)絡編程_第3頁](http://file4.renrendoc.com/view12/M05/23/01/wKhkGWZ8CQ6AW_nQAAGZ54Gh1w40373.jpg)
![《PHP》課件模塊九 網(wǎng)絡編程_第4頁](http://file4.renrendoc.com/view12/M05/23/01/wKhkGWZ8CQ6AW_nQAAGZ54Gh1w40374.jpg)
![《PHP》課件模塊九 網(wǎng)絡編程_第5頁](http://file4.renrendoc.com/view12/M05/23/01/wKhkGWZ8CQ6AW_nQAAGZ54Gh1w40375.jpg)
版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
計算機網(wǎng)絡20世紀60年代出現(xiàn),經(jīng)歷了20世紀70年代、80年代和90年代的發(fā)展,進入21世紀后,計算機網(wǎng)絡已經(jīng)成為信息社會的基礎設施,深入到人類社會的方方面面,與人們的工作、學習和生活息息相關。計算機網(wǎng)絡是通過傳輸介質(zhì)、通信設施和網(wǎng)絡通信協(xié)議,把分散在不同地點的計算機設備互連起來的,實現(xiàn)資源共享和數(shù)據(jù)傳輸?shù)南到y(tǒng)。網(wǎng)絡編程,就是在一定的協(xié)議下,實現(xiàn)多臺設備(計算機)之間通信的程序。Java語言對網(wǎng)絡編程提供了良好的支持。通過其提供的接口我們可以很方便地進行網(wǎng)絡編程。本模塊通過“文件上傳”案例介紹網(wǎng)絡編程的過程。模塊介紹思維導圖教學大綱能力目標◎能夠編寫TCP協(xié)議下的數(shù)據(jù)傳輸程序知識目標◎了解網(wǎng)絡通信協(xié)議◎理解TCP和UDP的協(xié)議特點◎掌握IP地址和端口號的作用◎熟悉TCP協(xié)議下兩個JDK常用類的使用◎掌握TCP通信的基本實現(xiàn)學習重點◎TCP通信的應用◎TCP通信程序的實現(xiàn)學習難點◎TCP通信“三次握手”過程◎TCP通信程序的實現(xiàn)任務9.1文件上傳程序設計任務目標了解網(wǎng)絡通信協(xié)議;理解TCP和UDP的協(xié)議特點;理解TCP協(xié)議下文件上傳過程;實現(xiàn)TCP協(xié)議下文件傳輸程序。任務9.1文件上傳程序設計網(wǎng)盤是由互聯(lián)網(wǎng)公司推出的在線存儲服務,它已經(jīng)融入了人們的日常生活中。人們在利用網(wǎng)盤上傳資料時,實際上是一個使用客戶端讀取本地文件,把文件上傳到服務器,服務器再把上傳的文件保存到服務器硬盤上的過程。本節(jié)要求了解網(wǎng)絡通信的基本原理,編寫使用TCP網(wǎng)絡通信程序,實現(xiàn)將客戶端的“c:\\1.jpg”文件上傳至服務器端的硬盤“d:\\upload\\”中。任務描述任務9.1文件上傳程序設計9.1.1網(wǎng)絡通信協(xié)議9.1.1.1網(wǎng)絡通信協(xié)議概述
要實現(xiàn)多臺計算機之間的通信,需要遵守一定的規(guī)則,如同人與人之間相互交流是需要遵循一定的規(guī)矩一樣,計算機之間能夠進行相互通信是因為它們都共同遵守一定的規(guī)則,即網(wǎng)絡通信協(xié)議。協(xié)議(protocol)是定義計算機如何通信的一組明確的規(guī)則,包括地址格式、數(shù)據(jù)如何分包等。針對網(wǎng)絡通信的不同方面,定義有很多不同的協(xié)議,如HTTP、FTP、TCP協(xié)議等。知識準備任務9.1文件上傳程序設計
通過網(wǎng)絡發(fā)送數(shù)據(jù)是一項復雜的操作,必須仔細地協(xié)調(diào)網(wǎng)絡的物理特性以及所發(fā)送數(shù)據(jù)的路徑特征。為了對應用程序開發(fā)人員和最終用戶隱藏這種復雜性,網(wǎng)絡通信的不同方面被分解為多個層。每一層表示為物理硬件(即線纜和電流)與所傳輸信息之間的不同抽象層次。在理論上,每一層只與緊挨其上和其下的層對話。將網(wǎng)絡分層,這樣就可以修改甚至替換某一層的軟件,只要層與層之間的接口保持不變,就不會影響到其他層。
TCP/IP協(xié)議(TransmissionControlProtocol/InternetProtocol,傳輸控制協(xié)議/因特網(wǎng)互聯(lián)協(xié)議)是Internet最基本、最廣泛的協(xié)議。它定義了計算機如何連入因特網(wǎng),以及數(shù)據(jù)如何在它們之間傳輸?shù)臉藴省K膬?nèi)部包含一系列的用于處理數(shù)據(jù)通信的協(xié)議,并采用了4層的分層模型,每一層都呼叫它的下一層所提供的協(xié)議來完成自己的需求,如圖9-1所示。任務9.1文件上傳程序設計
圖9-1中,TCP/IP協(xié)議中的四層分別是應用層、傳輸層、網(wǎng)絡層和鏈路層,每層分別負責不同的通信功能。鏈路層是用于定義物理傳輸通道,通常是對某些網(wǎng)絡連接設備的驅(qū)動協(xié)議,例如針對光纖、網(wǎng)絡提供的驅(qū)動。網(wǎng)絡層是整個TCP/IP的核心,它主要用于將傳輸?shù)臄?shù)據(jù)進行分組,將分組數(shù)據(jù)發(fā)送到目標計算機或者網(wǎng)絡。傳輸層主要使網(wǎng)絡程序進行通信,在進行網(wǎng)絡通信時,可以采用TCP協(xié)議,也可以采用UDP協(xié)議。應用層主要負責應用程序的協(xié)議,例如HTTP協(xié)議、FTP協(xié)議等。圖9-1TCP/IP網(wǎng)絡模型在JDK中提供了包用于專注網(wǎng)絡程序開發(fā),包中提供了兩種常見的網(wǎng)絡協(xié)議支持,分別是TCP和UDP。任務9.1文件上傳程序設計9.1.1.2TCP協(xié)議
TCP(TransmissionControlProtocol)全稱是傳輸控制協(xié)議,是一種面向連接的通信協(xié)議,即傳輸數(shù)據(jù)之前,在發(fā)送端和接收端建立邏輯連接,然后再傳輸數(shù)據(jù),它提供了兩臺計算機之間可靠無差錯的數(shù)據(jù)傳輸。在TCP協(xié)議中,在發(fā)送數(shù)據(jù)的準備階段,客戶端與服務器之間的三次交互,以保證連接的可靠,這三次交互被稱為“三次握手”?!叭挝帐帧钡木唧w過程如下:·第一次握手,客戶端向服務器端發(fā)出連接請求,等待服務器確認。·第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了連接請求?!さ谌挝帐?,客戶端再次向服務器端發(fā)送確認信息,確認連接。
整個交互過程如圖9-2所示。任務9.1文件上傳程序設計
完成三次握手,連接建立之后,客戶端和服務器就可以進行數(shù)據(jù)傳輸了。由于面向連接的特性,TCP協(xié)議可以保證傳輸數(shù)據(jù)的安全,所以應用十分廣泛,例如下載文件、瀏覽網(wǎng)頁等。圖9-2TCP協(xié)議通信——“三次握手”任務9.1文件上傳程序設計9.1.1.3UDP協(xié)議
UDP(UserDatagramProtocol)全稱是用戶數(shù)據(jù)報協(xié)議,是一種面向無連接的協(xié)議,即在使用UDP協(xié)議傳輸數(shù)據(jù)時,數(shù)據(jù)的發(fā)送端和接收端不需要建立邏輯連接。簡單的說,就是當一臺計算機向另一臺計算機發(fā)送數(shù)據(jù)時,發(fā)送端不會確認接收端是否存在,可以直接將數(shù)據(jù)、數(shù)據(jù)源和目的地都封裝在數(shù)據(jù)包中發(fā)送出去。同樣接收端在收到數(shù)據(jù)時,也不會向發(fā)送端反饋是否收到數(shù)據(jù)。和TCP不同的是,UDP不需要在發(fā)送數(shù)據(jù)前進行三次握手建立連接,只要想發(fā)數(shù)據(jù)就可以發(fā)送數(shù)據(jù),只是數(shù)據(jù)的搬運工,不會對數(shù)據(jù)報文進行任何拆分和拼接操作。任務9.1文件上傳程序設計
正由于無連接性,UDP不能保證數(shù)據(jù)的完整性,具有不可靠性。另外,UDP沒有擁塞控制,一直會以恒定的速度發(fā)送數(shù)據(jù),即使網(wǎng)絡條件不好,也不會對發(fā)送速率進行調(diào)整,那么在網(wǎng)絡條件不好的情況下可能產(chǎn)生丟包,因此在傳輸重要數(shù)據(jù)時不建議使用UDP協(xié)議,以免丟失重要數(shù)據(jù)。但是其優(yōu)點也很明顯,使用UDP協(xié)議消耗的資源小,每個數(shù)據(jù)包的大小限制在64k以內(nèi),通信效率高,所以通常會用于音頻、視頻這些實時性要求高的場景。例如視頻會議、群聊天等這些即使偶爾丟失一兩個數(shù)據(jù)包,也不會對接收結(jié)果產(chǎn)生太大影響的應用。任務9.1文件上傳程序設計TCPUDP是否連接面向連接無連接是否可靠可靠傳輸,使用流量控制和塞控制不可靠傳輸,不使用流量控制和塞控制對象數(shù)量只支持一對一通信支持一對一,一對多,多對一和多對多交互通信適用場景適用于要求可靠傳輸?shù)膽?,如文件傳輸適用于實時應用,如IP電話、視頻會議、直播等表9-1TCP和UDP的對比任務9.1文件上傳程序設計9.1.1.4IP地址和端口號
在Java中,網(wǎng)絡編程需要掌握三個要素,除了協(xié)議以外,還有IP地址和端口號。網(wǎng)絡的通信,本質(zhì)上是兩個進程(應用程序)的通信。“協(xié)議+IP地址+端口號”三元組合可以標識網(wǎng)絡中的進程,那么進程就可以利用這個標識與其它進程進行交互。
IP地址是InternetProtocolAddress的簡寫,指的是互聯(lián)網(wǎng)協(xié)議地址,用來給一個網(wǎng)絡中的計算機設備做唯一的編號。假如我們把“個人電腦”比作“一臺電話”的話,那么“IP地址”就相當于“電話號碼”。IP地址分為IPv4和IPv6。IPv4是一個32位的二進制數(shù),通常被分為4個字節(jié),表示成a.b.c.d的形式,例如00。其中a、b、c、d都是0~255之間的十進制整數(shù),那么最多可以表示42億個。由于互聯(lián)網(wǎng)的蓬勃發(fā)展,互聯(lián)網(wǎng)對IP地址的需求量愈來愈大,但是網(wǎng)絡地址資源有限,使得IP的分配越發(fā)緊張。為了擴大地址空間,擬通過IPv6重新定義地址空間,采用128位地址長度,每16個字節(jié)一組,分成8組十六進制數(shù),表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,以解決了網(wǎng)絡地址資源數(shù)量不夠的問題。任務9.1文件上傳程序設計
如果說IP地址可以唯一標識網(wǎng)絡中的設備,那么端口號就可以唯一標識設備中的進程(應用程序)了。端口號是一個邏輯端口,它用兩個字節(jié)表示的整數(shù),取值范圍是0~65535。每當打開一個網(wǎng)絡軟件,操作系統(tǒng)都會為網(wǎng)絡軟件分配一個隨機的或者是系統(tǒng)要指定的端口號。0~1023之間的端口號都已經(jīng)被用于一些知名的網(wǎng)絡服務和應用,普通的應用程序需要使用1024以上的端口號。如果端口號被另外一個服務或應用所占用,會導致當前程序啟動失敗。任務9.1文件上傳程序設計9.1.2TCP通信程序設計
TCP通信能實現(xiàn)兩臺計算機之間的數(shù)據(jù)交互,TCP連接時必須明確服務器端(Server)與客戶端(Client)。兩端通信時,服務端程序需要事先啟動,它不可以主動連接客戶端,只能等待客戶端的連接。然后客戶端主動連接服務器端,連接成功才能通信。連接過程中包含一個IO字節(jié)流對象,客戶端和服務端就用這個IO流對象進行通信。需要注意的是,當多個客戶端同時和服務端交互時,服務端必須明確和哪個客戶端進行交互,并且需要使用多個IO流對象。
Java在net包中提供了兩個類用于實現(xiàn)TCP通信程序。任務9.1文件上傳程序設計
(1)表示服務端的類:.ServerSocket類表示。該類實現(xiàn)了服務器套接字,套接字指的是兩臺設備之間通訊的端點。創(chuàng)建ServerSocket對象,相當于開啟一個服務,該對象等待通過網(wǎng)絡的請求,也就是等待客戶端的連接。ServerSocket類的主要構造方法和成員方法如表9-2所示。表9-2ServerSocket類的主要構造方法和成員方法方法聲明功能描述publicServerSocket(intport)使用該構造方法在創(chuàng)建ServerSocket對象時,就可以將其綁定到一個指定的端口號上,參數(shù)port就是端口號。publicSocketaccept()偵聽并接受連接,返回一個新的Socket對象,用于和客戶端實現(xiàn)通信。該方法會一直阻塞直到建立連接。任務9.1文件上傳程序設計
(2)表示客戶端的類:.Socket類表示。該類實現(xiàn)客戶端套接字。創(chuàng)建Socket對象,向服務端發(fā)出連接請求,服務端響應請求,兩者建立連接開始通信。Socket類的主要構造方法和成員方法如表9-3所示。表9-3Socket類的主要構造方法和成員方法方法聲明功能描述publicSocket(Stringhost,intport)創(chuàng)建套接字對象并將其連接到指定主機上的指定端口號。如果指定的host是null,則相當于指定地址為回送地址。publicInputStreamgetInputStream()返回此套接字的輸入流。關閉生成的InputStream也將關閉相關的Socket。publicOutputStreamgetOutputStream()返回此套接字的輸出流。關閉生成的OutputStream也將關閉相關的Socket。publicvoidclose()關閉此套接字。一旦一個socket被關閉,它不可再使用。關閉此socket也將關閉相關的InputStream和OutputStream。publicvoidshutdownOutput()禁用此套接字的輸出流。任何先前寫出的數(shù)據(jù)將被發(fā)送,隨后終止輸出流。任務9.1文件上傳程序設計
從通信邏輯上來看,TCP網(wǎng)絡通信的兩端程序編寫主要步驟如下:①服務端啟動,創(chuàng)建ServerSocket對象,指定端口號,等待連接。②客戶端啟動,創(chuàng)建Socket對象,構造方法綁定服務器的IP地址和端口號,請求連接。③服務端接收連接,調(diào)用ServerSocket對象中的accept()方法,返回請求的客戶端對象Socket。④客戶端使用Socket對象的getOutputStream()方法獲取網(wǎng)絡字節(jié)輸出流OutputStream對象,然后使用網(wǎng)絡字節(jié)輸出流OutputStream對象中的write()方法,給服務器發(fā)送數(shù)據(jù)。⑤服務端使用Scoket對象的getInputStream()方法獲取網(wǎng)絡字節(jié)輸入流InputStream對象,然后使用網(wǎng)絡字節(jié)輸入流InputStream對象中的read()方法,讀取客戶端發(fā)送的數(shù)據(jù)。到此,客戶端向服務端發(fā)送數(shù)據(jù)成功,接下來服務端向客戶端回寫數(shù)據(jù)。任務9.1文件上傳程序設計⑥服務端使用Socket對象中的getOutputStream()方法獲取網(wǎng)絡字節(jié)輸出流OutputStream對象,然后使用網(wǎng)絡字節(jié)輸出流OutputStream對象中的write()方法,給客戶端回寫數(shù)據(jù)。⑦客戶端使用Scoket對象的getInputStream()方法獲取網(wǎng)絡字節(jié)輸入流InputStream對象,然后使用網(wǎng)絡字節(jié)輸入流InputStream對象中的read()方法,讀取服務端回寫的數(shù)據(jù)。⑧客戶端釋放Socket資源,斷開連接。⑨服務端釋放Socket和ServerSocket資源。圖9-3TCP網(wǎng)絡通信邏輯圖任務9.1文件上傳程序設計
需要注意的是,客戶端和服務端交互時必須使用Socket中提供的網(wǎng)絡流,不允許使用自己創(chuàng)建的流對象。當創(chuàng)建客戶端對象Socket的時候,就會主動請求服務器,要求經(jīng)過3次握手建立連接通路。如果此時服務器沒有啟動,則會拋出連接被拒絕的異常(ConnectException:Connectionrefused:connect);如果服務器已經(jīng)啟動,那么交互就可以順利進行了。任務9.1文件上傳程序設計
接下來用一個案例來演示TCP網(wǎng)絡通信程序的編寫過程,服務器端程序如例9-1所示,客戶端程序如例9-2所示。importjava.io.*;import.*;publicclassExample9_1{publicstaticvoidmain(String[]args)throwsIOException{//1.創(chuàng)建ServerSocket對象,綁定端口,開始等待連接。ServerSocketserver=newServerSocket(8888);//2.接收連接,使用accept方法,返回socket對象。Socketsocket=server.accept();//3.通過socket獲取輸入流InputStreamis=socket.getInputStream();//4.一次性讀取數(shù)據(jù)//4.1創(chuàng)建字節(jié)數(shù)組byte[]bytes=newbyte[1024];//4.2將數(shù)據(jù)讀取到字節(jié)數(shù)組中intlen=is.read(bytes);//4.3解析數(shù)組,打印字符串信息System.out.println(newString(bytes,0,len));
例9-1Example9_1.java任務9.1文件上傳程序設計/*----------服務端回寫數(shù)據(jù)-----------*///5.通過socket獲取輸出流OutputStreamos=socket.getOutputStream();//6.回寫數(shù)據(jù)os.write("收到,謝謝".getBytes());//7.關閉資源socket.close();server.close();}}例9-1Example9_1.java任務9.1文件上傳程序設計importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;import.Socket;publicclassExample9_2{publicstaticvoidmain(String[]args)throwsIOException{//1.創(chuàng)建Socket(ip,port),確定連接到哪里。Socketsocket=newSocket("",8888);//2.通過Scoket,獲取輸出流對象OutputStreamos=socket.getOutputStream();//3.寫出數(shù)據(jù)os.write("你好,服務器".getBytes());/*----------客戶端解析服務端的回寫數(shù)據(jù)-----------*///4.通過Scoket,獲取輸入流對象。InputStreamis=socket.getInputStream();//5.讀取數(shù)據(jù)byte[]bytes=newbyte[1024];intlen=is.read(bytes);System.out.println(newString(bytes,0,len));//6.關閉資源socket.close();}}例9-2Example9_2.java任務9.1文件上傳程序設計
完成程序編寫后,首先運行服務器端程序Example9_1.java,然后運行客戶端程序Example9_2.java。從這兩個例子的運行結(jié)果中看到,服務器端結(jié)果顯示“你好,服務器”,表示收到來自客戶端的數(shù)據(jù)信息,如圖9-4所示??蛻舳私Y(jié)果顯示“收到,謝謝”,表示收到來自服務器端的回寫數(shù)據(jù),如圖9-5所示。圖9-4Example9_1運行結(jié)果(服務器端)圖9-5Example9_2運行結(jié)果(客戶端)任務實施1.任務分析文件上傳的原理,本質(zhì)上就是文件的復制??蛻舳撕头掌骱捅镜赜脖P進行讀寫,需要使用自己創(chuàng)建的字節(jié)流對象,即本地IO流??蛻舳撕头掌髦g進行讀寫,必須使用Socket中提供的字節(jié)流對象,即網(wǎng)絡IO流。除了明確字節(jié)流對象,還要明確數(shù)據(jù)源和目的地。客戶端的數(shù)據(jù)源是客戶端文件所在地址,目的地是服務器;服務端的數(shù)據(jù)源是客戶端上傳的文件,目的地是服務器的硬盤,即要存放文件的地址。文件上傳的過程如圖9-6所示。任務9.1文件上傳程序設計(1)客戶端使用本地字節(jié)輸入流,讀取要上傳的文件;(2)客戶端使用網(wǎng)絡字節(jié)輸出流,把讀取到的文件上傳到服務器;(3)服務器使用網(wǎng)絡字節(jié)輸入流,讀取客戶端上傳的文件;(4)服務器使用本地字節(jié)輸出流,把讀取到的文件,保存到服務器的硬盤上;(5)服務器使用網(wǎng)絡字節(jié)輸出流,給客戶端回寫一個“上傳成功”的提示;(6)客戶端使用網(wǎng)絡字節(jié)輸入流,讀取服務器回寫的數(shù)據(jù);(7)釋放資源。任務9.1文件上傳程序設計圖9-6文件上傳過程2.具體實現(xiàn)步驟(1)客戶端實現(xiàn)步驟:①創(chuàng)建一個本地字節(jié)輸入流FileInputStream對象,構造方法中綁定要讀取的數(shù)據(jù)源。②創(chuàng)建一個客戶端Socket對象,構造方法中綁定服務器的IP地址和端口號。③使用Socket中的getOutputStream()方法,獲取網(wǎng)絡字節(jié)輸出流OutputStream對象。④使用本地字節(jié)輸入流FileInputStream對象中的read()方法,讀取本地文件。⑤使用網(wǎng)絡字節(jié)輸出流OutputStream對象中的write()方法,把讀取到的文件上傳到服務器。⑥使用Socket中的方法getInputStream,獲取網(wǎng)絡字節(jié)輸入流InputStream對象。⑦使用網(wǎng)絡字節(jié)輸入流InputStream對象中的read()方法讀取服務回寫的數(shù)據(jù)。⑧釋放資源(FileInputStream,Socket)。任務9.1文件上傳程序設計2.具體實現(xiàn)步驟(2)服務端實現(xiàn)步驟:①創(chuàng)建一個服務器ServerSocket對象,和系統(tǒng)要指定的端口號。②使用ServerSocket對象中的accept()方法,獲取到請求的客戶端Socket對象。③使用Socket對象中的方法getInputStream,獲取到InputStream對象。④判斷d:\\upload文件夾是否存在,不存在則創(chuàng)建。⑤創(chuàng)建一個FileOutputStream對象,構造方法中綁定要輸出的目的地。⑥使用InputStream對象中的方法read,讀取客戶端上傳的文件。⑦使用FileOutputStream對象中的write()方法,把讀取到的文件保存到服務器的硬盤上。⑧使用Socket對象中的getOutputStream()方法,獲取到網(wǎng)絡字節(jié)輸出流OutputStream對象。⑨使用網(wǎng)絡字節(jié)輸出流OutputStream對象中的write()方法,給客戶端回寫“上傳成功”。⑩釋放資源(FileOutputStream,Socket,ServerSocket)。任務9.1文件上傳程序設計3.程序編寫服務器端程序如例9-3所示,客戶端程序如例9-4所示。任務9.1文件上傳程序設計importjava.io.*;import.*;publicclassExample9_4{publicstaticvoidmain(String[]args)throwsIOException{//1.創(chuàng)建服務器,指定端口號ServerSocketserver=newServerSocket(8888);//2.獲取到請求的客戶端Socketsocket=server.accept();//3.獲取到網(wǎng)絡字節(jié)輸入流InputStreamis=socket.getInputStream();//4.判斷d:\\upload文件夾是否存在,不存在則創(chuàng)建Filefile=newFile("d:\\upload");if(!file.exists()){file.mkdirs();}//5.創(chuàng)建一個本地字節(jié)輸出流,綁定要輸出的目的地FileOutputStreamfos=newFileOutputStream(file+"\\1.jpg");//6.使用網(wǎng)絡字節(jié)輸入流讀取客戶端上傳的文件intlen=0;
任務9.1文件上傳程序設計byte[]bytes=newbyte[1024];while((len=is.read(bytes))!=-1){//7.使用本地字節(jié)輸出流,把讀取到的文件保存到服務器的硬盤上fos.write(bytes,0,len);}//8.獲取到網(wǎng)絡字節(jié)輸出流//9.使用網(wǎng)絡字節(jié)輸出流,給客戶端回寫“上傳成功”socket.getOutputStream().write("上傳成功".getBytes());//10.釋放資源fos.close();socket.close();server.close();}}任務9.1文件上傳程序設計importjava.io.*;import.Socket;publicclassExample9_4{publicstaticvoidmain(String[]args)throwsIOException{//1.創(chuàng)建本地字節(jié)輸入流,綁定要讀取的數(shù)據(jù)源FileInputStreamfis=newFileInputStream("c:\\1.jpg");//2.創(chuàng)建客戶端對象,綁定服務器IP地址和端口號Socketsocket=newSocket("",8888);//3.獲取網(wǎng)絡字節(jié)輸出流OutputStreamos=socket.getOutputStream();//4.讀取本地文件intlen=0;byte[]bytes=newbyte[1024];while((len=fis.read(bytes))!=-1){//5.把讀取到的文件上傳到服務器os.write(bytes,0,len);}//6.獲取網(wǎng)絡字節(jié)輸入流InputStreamis=socket.getInputStream();//7.讀取服務回寫的數(shù)據(jù)while((len=is.read(bytes))!=-1){System.out.println(newString(bytes,0,len));例9-4Example9_4.java}//8.釋放資源fis.close();socket.close();}}
完成程序編寫后,按“先運行服務器端,后運行客戶端”的順序運行程序,能夠看到D盤中生成了一個名為“upload”的文件夾,里面的存放了一個文件,該文件與“c:\\1.jpg”文件一致,說明實現(xiàn)了文件的上傳。
需要注意的是,上述代碼雖然實現(xiàn)了文件的上傳,但無論是客戶端還是服務器端,程序都沒有停止運行,這是因為受到FileInputStream類的read()方法影響。通過查看API手冊可以知道,read(byte[]b)方法功能是“從此輸入流中將最多b.length個字節(jié)數(shù)據(jù)讀入一個byte數(shù)組中,在某些輸入可用之前,此方法將阻塞”。在例9-3代碼中,客戶端中的fis.read(bytes)讀取本地文件,讀取到-1則結(jié)束,然而在while循環(huán)里并不會讀取到-1,也就不會把結(jié)束標記寫給服務器端。服務器端中的is.read(bytes)用于讀取客戶端上傳的文件,但由于讀不到文件的結(jié)束標志,read()方法就會進入到阻塞狀態(tài),一直死循環(huán)等待結(jié)束標記。同樣的,客戶端中的is.read(bytes)也會因為讀取不到服務器回寫的數(shù)據(jù)而進入阻塞狀態(tài)。
為了能夠更加直觀看出阻塞現(xiàn)象,現(xiàn)分別對例9-3和例9-4的代碼進行修改。任務9.1文件上傳程序設計任務9.1文件上傳程序設計publicclassExample9_3{publicstaticvoidmain(String[]args)throwsIOException{……//省略例9-3重復代碼
System.out.println("服務器端阻塞測試");while((len=is.read(bytes))!=-1){fos.write(bytes,0,len);}
System.out.println("若此語句出現(xiàn),則說明服務器端未發(fā)生阻塞");……}}修改例9-3Example9_3.java任務9.1文件上傳程序設計publicclassExample9_4{publicstaticvoidmain(String[]args)throwsIOException{……//省略例9-4重復代碼System.out.println("客戶端阻塞測試");while((len=is.read(bytes))!=-1){System.out.println(newString(bytes,0,len));}
System.out.println("若此語句出現(xiàn),則說明客戶端未發(fā)生阻塞");……}}修改例9-4Example9_4.java
修改后的例9-3和例9-4運行結(jié)果分別如圖9-7和圖9-8所示,可以看到服務器端打印輸出語句“服務器端阻塞測試”,但沒有出現(xiàn)“若此語句出現(xiàn),則說明服務器端未發(fā)生阻塞”;客戶端打印輸出“客戶端阻塞測試”,但沒有出現(xiàn)“若此語句出現(xiàn),則說明客戶器端未發(fā)生阻塞”,說明服務器端和客戶端均在while中產(chǎn)生了死循環(huán),發(fā)生了阻塞現(xiàn)象。任務9.1文件上傳程序設計圖9-7Example9_3修改后的運行結(jié)果(服務器端)圖9-8Example9_4修改后的運行結(jié)果(客戶端)
那么如何解決上述的阻塞問題呢?由于阻塞問題是由于服務器端沒有讀到結(jié)束標記造成的,所以在上傳文件后,只需要給服務器寫一個結(jié)束標記就可以解決問題了。在這里需要用到socket類的shutdownOutput()方法,此方法的作用是禁用此套接字的輸出流。對于TCP套接字,任何以前寫入的數(shù)據(jù)都將被發(fā)送,并且后跟TCP的正常連接終止序列?,F(xiàn)對例9-4的代碼再次進行修改。任務9.1文件上傳程序設計任務9.1文件上傳程序設計publicclassExample9_4{publicstaticvoidmain(String[]args)throwsIOException{……//省略例9-4重復代碼while((len=fis.read(bytes))!=-1){os.write(bytes,0,len);}socket.shutdownOutput();InputStreamis=socket.getInputStream();System.out.println("客戶端阻塞測試");while((len=is.read(bytes))!=-1){System.out.println(newString(bytes,0,len));}System.out.println("若此語句出現(xiàn),則說明客戶端未發(fā)生阻塞");……}}再次修改例9-4Example9_4.java
修改完成后,重新運行例9-3和例9-4程序,其運行結(jié)果分別如圖9-9和圖9-10所示??梢钥吹椒掌鞫舜蛴≥敵稣Z句“服務器端阻塞測試”、“若此語句出現(xiàn),則說明服務器端未發(fā)生阻塞”,;客戶端打印輸出“客戶端阻塞測試”、“上傳成功”、“若此語句出現(xiàn),則說明客戶器端未發(fā)生阻塞”,但沒有出現(xiàn)“若此語句出現(xiàn),則說明客戶器端未發(fā)生阻塞”,并且程序在完成文件的上傳后停止運行,說明成功解決了阻塞問題。任務9.1文件上傳程序設計圖9-9Example9_3的運行結(jié)果(服務器端)圖9-10Example9_4的運行結(jié)果(客戶端)4.程序優(yōu)化
現(xiàn)對文件上傳進行優(yōu)化,以解決以下兩個問題:
(1)文件名稱寫死的問題。在服務器端中,保存文件的名稱如果寫死,那么最終導致服務器硬盤只會保留一個文件。建議使用系統(tǒng)時間優(yōu)化,保證文件名稱唯一。
(2)循環(huán)接收的問題。在前面的程序中,服務器端只保存一個文件就關閉了,之后的用戶無法再上傳,這是不符合實際的。使用循環(huán)改進,可以不斷的接收不同用戶的文件。
(3)效率問題。如果多個人需要同時上傳文件時,且文件較大時,服務端每接收一個文件可能會耗費幾秒鐘的時間,此時不能接收其他用戶上傳,那么效率就會非常低??梢允褂枚嗑€程技術進行優(yōu)化。
修改后的服務端代碼如例9-5所示。任務9.1文件上傳程序設計任務9.1文件上傳程序設計importjava.io.*;import.*;importjava.util.Random;publicclassExample9_5{publicstaticvoidmain(String[]args)throwsIOException{ServerSocketserver=newServerSocket(8888);//優(yōu)化2:讓服務器一直處于監(jiān)聽狀態(tài)//有一個客戶端上傳文件,就保存一個文件while(true){Socketsocket=server.accept();//優(yōu)化3:使用多線程技術,提高程序的效率//有一個客戶端上傳文件,就開啟一個線程,完成文件的上傳newThread(newRunnable(){//完成文件的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度水稻種植保險配套收購合同范本
- 2025年度項目管理聘用合同解除協(xié)議
- 2025-2030年廚電在線維修預約行業(yè)深度調(diào)研及發(fā)展戰(zhàn)略咨詢報告
- 2025-2030年抗疲勞保健飲料行業(yè)跨境出海戰(zhàn)略研究報告
- 2025年弓鋸項目可行性研究報告
- 2025年鍍鉻球頂全翻蓋豪華宴會湯爐項目可行性研究報告
- 2025年轉(zhuǎn)速監(jiān)控開關項目可行性研究報告
- 2025年中國暗裝鉸鏈市場調(diào)查研究報告
- 2025年甘草粉項目可行性研究報告
- 2025年吊頂板項目可行性研究報告
- 鋰離子電池健康評估及剩余使用壽命預測方法研究
- c30混凝土路面施工方案
- 頸椎骨折的護理常規(guī)課件
- 電商運營銷售計劃Excel模版
- 2022-2023學年上海市楊浦區(qū)上海同濟大附屬存志學校七年級數(shù)學第二學期期中綜合測試模擬試題含解析
- 稿件修改說明(模板)
- GB/T 33107-2016工業(yè)用碳酸二甲酯
- GB/T 16604-2017滌綸工業(yè)長絲
- 勞動合同法經(jīng)典講義
- 工時定額編制標準(焊接)
- 三位數(shù)乘一位數(shù)練習題(精選100道)
評論
0/150
提交評論