Java學習總結-網絡.

分類:IT技術 時間:2016-10-11
作為一個剛學習編程的新手,發現學習中存在的問題就是:急功近利,什麽東西都希望花少量的時間盡快掌握,所以省去很多必不可少的工作,比如:勤思考、勤動手、做筆記等,導致荒廢一段時間後,相關知識點都忘了,所以現在又溫習以前看的教程,並把相關內容記錄下來。
這一篇是學習網絡編程的日誌,在開始學習之前,我盡量以一個編程白癡的角度,把我的心路歷程記錄下來,我覺的從一個編程小白到入門級新手是一個很短的距離。

           既然學習網絡,首先我們要考慮到的就是:

    1、網絡是什麽或者網絡編程的基礎?

         作為一個21世紀的人,對於這個問題,肯定能聯想或者回答點什麽,比如網絡就是要有網線、設備(專業術士:終端),比如臺式電腦(PC)、手機、IPad、電視等,似乎只能想到這些了,但是作為一個編程的人員,似乎要了解的更加深入和具體一點,因為以上內容並不能支持你去完成編程。

         這需要不斷的提出問題,從各個可能角度去了解,比如:

  1.  網絡的實際工作是什麽?答:完成信息的傳遞.
  2. 舉例信息傳遞的一個正式場景?答:通過QQ給好友發送信息,或者查看門戶網站的新聞。
  3.  假設讓你來設計QQ,怎麽完成給某個好友發信息?答:首先我要知道這個好友在網絡上位置,我們知道通過IP,但是這個信息發到好友的PC上,怎麽到的QQ,而不是feiQ、MSN或者其它任何可以接受信息的軟件上的呢?
  4. 假設我的好友不在線,我發送信息過去怎麽辦?答:發送失敗,返回一個提示給你。

 

以上問題的思考,引入我們網絡編程專業知識的介紹:

 

  • 網絡模型

1、 什麽是網絡模型?

個人理解:模型是把還未存在或者抽象的東西用更具體的方式表現出來;所以網絡模型是把信息傳輸過程中相關的軟硬件,按功能進行劃分,便於我們清晰的了解網絡。

OSI模型,所謂的七層模型,早期的。

關於OSI模型各層的功能,在百科上有詳細的介紹,但是比較難以理解和記憶,所以根據畢向東老師的視頻,做一下簡單的記錄:

1、  物理層:可以理解為網絡中的物理媒介,比如網線,用於比特流的傳輸。

2、  數據鏈路層:主要將物理層接收的MAC地址進行封裝和解封裝,主要設備就是交換機。

3、  網絡層:將下層接收到的數據進行IP地址的封裝與解封裝,主要設備就是路由器。

4、  傳輸層:定義了一些傳輸的協議和端口號,我們主要學習的內容。

5、  會話層:通過傳輸層(傳輸端口和接收端口)建立數據傳輸的通路。

6、  表示層:對於接收的數據進行解釋、加密和解密、壓縮和解壓縮,就是把二進制變成文字、圖片、聲音等。

7、  應用層:指計算機上的應用軟件,比如FTP、瀏覽器、QQ,它們其實就是數據解析器。


封包:首先,軟件發送信息後,應用層需要帶上該軟件的標識,然後表示層把解析數據,明確發送的是圖標、聲音等,接著會話層需要明確與誰建立通話,傳輸層明確使用什麽協議傳輸,網絡層需要確定發送到IP地址,數據鏈路層中交換機根據IP綁定對應的MAC地址,物理層把信息變成二進制流進行傳輸。

拆包:對方物理層接收二進制流,數據鏈路層查看MAC地址是否與本機一致,網絡層查看IP地址是否與本機一致,傳輸層明確查看是什麽協議,會話層查看與那個應用建立的回話,表示層查看發送的什麽內容,應用層查看那個應用接收數據並解析。

 

TCP/IP模型,四層結構,可理解為了簡化七層模型而提出的,兩者模型的對照關系如下:

(應用層、表示層、會話層)變成“應用層”,(物理層、數據鏈路層)變成“主機至網絡層”,又稱網絡接口層,其中網絡層和傳輸層沒變,這兩個層比較重要。

關於這張圖,是對TCP/IP模型直觀的描述,首先網絡接口層,所謂的網絡接口1、2、3,可以看做是交換機的中轉特性,網際層主要是IP的封裝,傳輸層主要是傳輸協議的綁定和解析,而應用層中不同協議的,如HTTP,可以看做是應用軟件通訊間的協議。

2、為什麽有了TCP/IP、UDP協議,還需要HTTP、STMP協議?

可以這樣理解,TCP/IP協議只是滿足了最原始數據的交互,但是有些應用軟件,比如瀏覽器,它需要解析HTML格式的數據,那麽解決辦法就是再建一個自身軟件相關的協議,當然這種協議都是針對廣泛的應用而誕生的,如郵件、網頁等,TCP/IP協議屬於比較底層的協議,HTTP是在此基礎上建立的協議。

 

  • 網絡通訊的要素

根據上面的學習,我們可以把網絡通訊中最關鍵的要素提取出來:

1、  信息發到哪裏,家住在哪裏?即計算機的地址,MAC或者IP,IP(Internet Protocol Address),不是IP協議。

2、  怎麽傳輸?用馬、飛鴿、自行車、摩托車還是其它工具?通訊方式(協議):TCP/IP、UDP。

3、  家裏哪一個人收?因為一家裏面住了很多人,信送到家裏需要指明收信人,同理,一臺計算機上有很多軟件,信息發過去,究竟是那個一個軟件接收,QQ還是feiQ?這就是端口號,比如瀏覽器默認是80端口。一個端口對應一個操作系統進程。

總結:三大要素分別為,IP地址、端口號、傳輸協議

 

1、 IP地址

是計算機在網絡中唯一的身份標識,就好比人的身份證一樣。IP一般由網絡運營商指定,區別於MAC地址,是可以改變的(可以重新指定)。

IP由四段組成,每段有8位二進制組成,最大值為255,現有IP組合個數為2的32次方,也只有42億,已經不滿足現有需要了,所以提出了IPv6。

本機的地址為:127.0.0.1,機器名為:localhost,每個網絡段都有一個廣播地址就是“xxx.xxx.xxx.255”,如果向這個IP發送信息,則該網段上所有機器都會接收信息。

2、 端口號

是應用軟件在計算機上的邏輯標識,更準確的說是進程在計算機中的標識,它不是真實的硬件端口,而是操作系統層面賦予軟件的邏輯地址,目的就是為把信息準確的發送給不同的進程。

         有效端口號的範圍:0~65535,其中0~1024是系統使用或者保留端口。

3、 傳輸協議

所謂協議就是規則,傳輸協議有兩種:TCP/IP和UDP

TCP/IP(傳輸控制協議),特點

1)        通過三次握手建立穩定的數據通道,所謂三次握手,就是發送端首先發送連接請求,接收端接收請求信息,這是第一次握手;然後接收端返回的信息表示:“接收到你的信息了”,這個信息又返回到發送端,這是第二次握手;最後發送還得發送信息:“接收到你返回的信息了”給接收端,這是第三次握手。

為什麽要三次握手,而不是兩次或者是四次?因為有可能在第二次握手後,發生斷網等異常,那麽發送信息就會失敗;為什麽不是四次,因為可以把3次看作是最少且合適的次數,四次可能是重復行為了。

2)        一次可以發送大量數據,沒有大小的限制。

UDP協議(數據報文協議),特點:

1)        發送端直接發送數據,事先不建立穩定色數據通道,數據可能會丟失,是不安全的。

2)        沒有發送端的數據大小最大只能為64K。

  • 域名解析

1、 什麽是域名?它的由來?

簡單的來說就是網址,比如www.googel.com,域名其實是IP的一個替代,因為正常訪問互聯網是需要那臺主機的IP地址的,比如10.0.0.100,但是大量的IP是不利於記憶的,需要用域名這種方式更加方便。

2、 域名解析的方式?

雖然我們在上層中使用的是域名,但是在網絡層,我們封裝的還是IP地址,所以首先需要把我們訪問的域名解釋為對應的IP,這個工作由DNS(域名解析服務)服務器來做,DNS服務器分為本地和互聯網上的,優先調用本地DNS服務

這個服務是調用的文件就是:C:\Windows\system32\drivers\etc\hosts:

本質上就是IP與域名的對應關系,在我們上網時,根據域名去對應到IP地址,然後根據IP地址去查找主機,同樣在我們配置IP地址時,有一個DNS地址,那個就是外網的DNS服務器地址,一般有網絡運營商提供。

2、在程序設計中,根據以上的內容,為我們提供哪些對應的類或者接口。

  • IP地址。

在Java中萬物即對象,所以看起來IP地址是一串字符串,並沒有成為對象的必要,但是在java確是對象,類名為InetAddress,包名:java.net。

1、  怎麽獲取一個InetAddress對象?

我們最熟悉的當時是字符串形式的,比如“192.168.0.1”,所以容易想到的就是對象初始化的時候,在構造函數中傳入該字符串,但是你查詢API發現該類並沒有構造函數,它其實是提供的靜態方式,接收字符串,返回InetAddress對象。


import java.net.*;
 
class IPDemo {
    
     public static voidmain(String[] args) throws UnknownHostException{
             
              //getByName()方法,接收字符串(可以為IP、主機名、域名),返回該IP對象
              InetAddress ip =InetAddress.getByName("www.Google.com");
              //getLoaclHost(),返回本機IP
              InetAddresslocal_ip = InetAddress.getLocalHost();               
             
              //getHostAddress(),返回IP地址的字符串形式,根據DNS解析規則
              String  str_ip = ip.getHostAddress();
              System.out.println(str_ip);
              //getHostName(),返回IP地址的主機名,沒有,則返回IP地址
              String str_name =ip.getHostName();
              System.out.println(str_ip);                        
             
     }
}


 

  • Socket

1、 為什麽現在不直接學習JAVA的中網絡編程的相關類,而是現在了解socket?

socket,專業術士叫套接字,當然沒必要糾結這個名字,重要的是它的由來,他是網絡編程的提出一種規範,也就是說它不是哪一種編程語言裏面提出的,而是所有編程語言在涉及到網絡編程,必須通過Socket機制實現,它淩駕於編程語言之上。

2、 socket機制有哪些特點?

首先socket,它是傳輸層、網絡層、網絡接口層向上為應用層提供的編程接口;

它接收網絡通訊的關鍵要素(IP、端口)和傳輸的數據,它底層自動完成相關通訊協議、IP封裝和解析、IO流轉換和傳輸;

通訊兩端都是必須是socket對象,而兩者之間的流,又可以稱為socket流,所以網絡編程又稱為socket編程。它就好比是兩個貨運碼頭,在發送端,你把IP、端口、數據信息放到socket中,在另外的接收端,同樣建立一個socket對象,並且只要指定它監聽本機的端口,就能接收到發送端信息。


3、 通訊要素中,關於通訊協議,比如UDP、TCP/IP,在socket是怎麽去體現或者是區別?

Java中不同協議的區別,並不是在一個socket類初始化的時候去指定的,而是為這兩者協議提供了不同的java類。

                  UDP:發送和接收端即為DatagramSocket。

                 TCP/IP:分為客戶端和服務端類,客戶端就是:Socket,而服務端是:ServerSocket。


  • UDP協議

首先查看JDK API文檔,java.net.DatagramSocket,此類表示用來發送和接收數據報包的套接字。

構造函數:

DatagramSocket

()

          構造數據報套接字並將其綁定到本地主機上任何可用的端口。

 

DatagramSocket

(int port)

          創建數據報套接字並將其綁定到本地主機上的指定端口。

 

發送方法:

void

send

(DatagramPacket p)

          從此套接字發送數據報包。

接收方法:

void

receive

(DatagramPacket p)

          從此套接字接收數據報包。

 

這裏要說明的不是我們想象中,直接接收IP、端口和數據,而是一個叫“DatagramPacket”的類,關於這個類我們查看API,說明如下:

DatagramPacket:此類表示數據報包,數據報包用來實現無連接包投遞服務。每條報文僅根據該包中包含的信息從一臺機器路由到另一臺機器。從一臺機器發送到另一臺機器的多個包可能選擇不同的路由,也可能按不同的順序到達。不對包投遞做出保證。

再查看它其中的構造函數

 

DatagramPacket

(byte[] buf,int length,
InetAddress
 address,int port)

構造數據報包,用來將長度為

length
的包發送到指定主機上的指定端口號。

 

備註:它其實就是把上面提到的信息封裝到一個叫數據報包的對象中,這樣我們在數據傳輸中其實是傳遞的數據報包,這種設計方式更加符合socket底層數據傳輸的真實情形。

 

DatagramPacket

(byte[] buf, int length)

          構造

DatagramPacket
,用來接收長度為
length
的數據包。

 

需要註意的是:

DatagramPacket
是分發送報包和接收報包,它的區別就是接收報包創建時,構造函數不需要傳入端口和IP。

 

UDP分為發送端接收端

1、 UDP發送端。

建立發送端的思路:

1)        創建socket對象,即DatagramSocket。

2)        創建需要傳輸的數據報包,即DatagramPocket對象,分別傳入需要傳輸的數據(字節數組)、字節數組的長度、IP對象、端口。

3)        調用socket的發送方法,即send(),傳入已創建的數據報包。

4)        關於socket流,即調用close()方法。

import java.net.*;
import java.io.*;
 
class UdpSend {
        
         public static voidmain(String[] args) throws IOException,UnknownHostException  {
                  
                   //創建socket對象
                   DatagramSocketds = new DatagramSocket(8888);
                  
                   //發送的信息
                   String info= "網絡編程,我來了!";
                  
                   byte[] buf =info.getBytes();
                  
                   //創建發送的數據包對象
                   DatagramPacketdp = new DatagramPacket(buf,buf.length,InetAddress.getLocalHost(),10000);
                  
                   //通過socket對象發送數據包
                   ds.send(dp);
                  
                   //關閉socket流對象
                   ds.close();
         }
}


2、 UDP接收端

 

建立接收端的思路:

1)        創建接收端sockect服務。

2)        創建接收端的數據包。

3)        通過socket服務的接收方法把數據存儲到數據包中。

4)        通過數據包的方法解析其中的數據

5)        關閉資源。

importjava.net.*;
importjava.io.*;
 
class UdpReceive{
        
         public static void main(String[] args)throws IOException,UnknownHostException {
                  
                   //創建socket對象,指定監聽端口10000
                   DatagramSocket ds = newDatagramSocket(10000);
                  
                   //定義一個字節數值用來接收信息
                   byte[] buf = new byte[1024];
                   System.out.println(dp.getLength());       
                   //創建接收的數據包對象
                   DatagramPacket dp = newDatagramPacket(buf,buf.length);
System.out.println(dp.getLength());       
                  
                   //通過socket對象接收數據包
                   ds.receive(dp);
                   System.out.println(dp.getLength());                
                  
                   //通過包的方法解析相關信息,比如IP、端口、信息
                   String ip =dp.getAddress().getHostAddress();
                   int port = dp.getPort();
                   String info = newString(dp.getData(),0,dp.getLength());                
                 
                   //打印接收到的信息
                   System.out.println(ip+","+port+","+info);
                  
                   //關閉socket流對象
                   ds.close();
         }
}


註意點:

1、  DatagramPacket對象構建是需要指定長度的,一般都為發送或者接收的字節數組的長度。

2、  在服務端中創建DatagramSocket對象,需要指定監聽的端口號;接收到的數據包中getPort()方法返回的是發送端主機的端口,即發送端示例中的8888,而不是10000。

3、  DatagramPacket的內部消息長度值在接收數據後會發生改變,變為實際接收到的數據的長度值

4、  如果發送端的數據為大量,則可以在服務端通過循環的方式接收,暫時沒有學習相關代碼。

 

importjava.net.*;
importjava.io.*;
 
 
class ChatClientimplements Runnable {
        
         public void run() {
 
                   try {
                            //創建socket對象
                            DatagramSocket ds=new DatagramSocket(8888);
                           
                            //鍵盤輸入流
                            BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
                           
                            //讀取字符
                            String line = null;
                            while(true){
                                     line =br.readLine();
                                    
 
                                     byte[] buf= line.getBytes();
                                    
                                     //創建發送的數據包對象
                                     DatagramPacketdp = new DatagramPacket(buf,buf.length,InetAddress.getLocalHost(),10000);
                                    
                                     //通過socket對象發送數據包
                                     ds.send(dp);    
 
                                     if(line.equals("886")){
                                               break;
                                     }
                                                                
                            }
        
                            //關閉socket流對象
                            ds.close();                 
                           
                   }catch(Exception e){
                           
                   }
                  
 
         }
}

importjava.net.*;
importjava.io.*;
 
class ChatServerimplements Runnable{
        
         public void run()  {
                  
                   try{
                            //創建socket對象,指定監聽端口10000
                            DatagramSocket ds =new DatagramSocket(10000);
                           
                            //定義一個字節數值用來接收信息
                            byte[] buf = newbyte[1024];
                           
                            //創建接收的數據包對象
                            DatagramPacket dp =new DatagramPacket(buf,buf.length);
                           
                            String info = null;
                            //通過socket對象接收數據包
                            while(true){
                                     ds.receive(dp);                  
                                    
                                     info = newString(dp.getData(),0,dp.getLength());
                                    
                                     //打印接收到的信息
                                     System.out.println(dp.getAddress().getHostAddress()+":"+info);
                            }
                   }catch(Exception e){
                           
                   }
 
         }
}

class ChatDemo {
        
         public static void main(String[] main){
                  
                   new Thread(newChatClient()).start();
                   new Thread(newChatServer()).start();
         }
}

  •  TCP

回顧一下tcp的主要特點,通過三次握手建立的穩定通道,進行數據的傳輸。

tcp的類在java中定義與UDP是不一樣的,它有兩個類:客戶端socket和服務端socket。

客戶端類:

Socket,此類實現客戶端套接字(也可以就叫“套接字”)。套接字是兩臺機器間通信的端點。

服務端類:

ServerSocket,此類實現服務器套接字。服務器套接字等待請求通過網絡傳入。它基於該請求執行某些操作,然後可能向請求者返回結果。 

 

1、 客戶端

首先查看客戶端類Socket的相關方法。

 構造函數

Socket

(InetAddress address,int port)

          創建一個流套接字並將其連接到指定 IP 地址的指定端口號。

Socket

(
String
 host, int port)

          創建一個流套接字並將其連接到指定主機上的指定端口號。

1)        接著我們要在API中查看相關的發送和接收方法,就跟UDP一樣,但是你發現並沒有,這是為什麽?

因為tcp是要建立傳輸通道的,那麽它是在什麽時候建立的呢,其實就是在我們創建Socket對象時,它就會嘗試建立通道,如果服務端沒有響應,那麽就會報錯;否則,建立數據通道,而數據通道本質上就是IO流,而且是雙向通道。所以我們會發現Socket類中有返回IO流的方法。      

返回輸出流

 
OutputStream

getOutputStream

()

          返回此套接字的輸出流。

返回輸入流

InputStream

getInputStream

()

          返回此套接字的輸入流。

  關閉此套接字

void

close

()

          關閉此套接字。

                  

                所以我們必須借助IO流,實現數據的讀寫操作。

 

客戶端的建立思路

1)        建立socket服務。

2)        返回socket的輸入流。

3)        通過IO流把傳輸信息寫入。

4)        關閉Socket資源。

 

importjava.net.*;
importjava.io.*;
 
classTCPClientDemo {
         public static void main(String[]args)  throwsSocketException,IOException{
                  
                   //1.建立socekt服務
                   Socket client = newSocket(InetAddress.getLocalHost(),10001);
                  
                   //2.返回輸出數據流
                   OutputStream out =client.getOutputStream();
                  
                   //3.創建傳輸數據
                   String str = "tcp客戶端:我來了!";
                  
                   //4.通過IO流的wirte()方法寫入傳輸數據
                   out.write(str.getBytes());
                  
                   //5.關閉資源
                   client.close();
         }
}


 

2、 服務端

查看服務端類ServerSocket的相關方法:

 構造函數

ServerSocket

()

          創建非綁定服務器套接字。

ServerSocket

(int port)

          創建綁定到特定端口的服務器套接字。

2)        我們會查看ServerSocket類中什麽方法返回InputStream類型,發現並沒有,這是為什麽?

因為TCP建立的是雙向通道,假如有多個客戶端給服務端發送數據,那麽服務端給客戶端返回數據的時候怎麽去處理,一個可能的辦法根據輸入的數據,獲取到它IP、端口,然後再去創建服務端?似乎行不的通。其實服務端socket可以獲取到輸入流,那麽我們在服務端如果能返回一個客戶端的Socket對象,這個Socket與客戶端形成一個輸入輸出的對應通道(理解很牽強)

所以就有了下面的方法:

f

 
Socket

accept

()

          偵聽並接受到此套接字的連接。

 

 關閉套接字

void

close

()

          關閉此套接字。

 

 

服務端的建立思路

1)        建立服務端socket。

2)        通過accept()返回客戶端的socket對象。

3)        通過socket對象返回輸入流。

4)        通過IO讀取其中的信息。

5)        關閉資源。


import java.net.*;
import java.io.*;
 
class TCPServerDemo {
         public static voidmain (String[] args) throws SocketException,IOException  {
                  
                   //1.建立socekt服務,監聽端口100001
                   ServerSocketserver = new ServerSocket(10001);
                  
                   //2.返回socekt對象
                   Socketsocket = server.accept();
                  
                   //3.獲取輸入流,轉為緩存字符流
                   InputStreamin = socket.getInputStream();
                  
                   BufferedReaderbufIn = new BufferedReader(new InputStreamReader(in));
                  
                   //4.獲取傳輸信息並打印
                   String info= bufIn.readLine();
                   System.out.println(info);
                  
                   //關閉資源
                   server.close();
         }
}


客戶端與服務端的交互

import java.net.*;
import java.io.*;
 
class TCPClientDemo {
         publicstatic void main(String[] args)  throwsSocketException,IOException{
                  
                   //1.建立socekt服務
                   Socketclient = new Socket(InetAddress.getLocalHost(),10002);
                  
                   //2.返回輸出數據流
                   OutputStreamout = client.getOutputStream();
                   //PrintWriterpwOut = new PrintWriter(out,true);
                   //3.創建傳輸數據
                   Stringstr = "tcp客戶端:我來了!"+"\r\n";
                  
                   //4.通過IO流的wirte()方法寫入傳輸數據
                   out.write(str.getBytes());
                   //pwOut.println(str);
 
                   //5.獲取輸入流,轉為緩存字符流
                   InputStreamin = client.getInputStream();
                   BufferedReaderbufIn = new BufferedReader(new InputStreamReader(in));
                  
                   //4.獲取服務端傳輸信息並打印
                   Stringinfo = bufIn.readLine();
                   System.out.println(info);
 
 
                   //5.關閉資源
                   client.close();
         }
}


import java.net.*;
import java.io.*;
 
class TCPServerDemo {
         publicstatic void main (String[] args) throws SocketException,IOException  {
                  
                   //1.建立socekt服務,監聽端口100001
                   ServerSocketserver = new ServerSocket(10002);
                  
                   //2.返回socekt對象
                   Socketsocket = server.accept();
                  
                   //3.獲取輸入流,轉為緩存字符流
                   InputStreamin = socket.getInputStream();            
                   BufferedReaderbufIn = new BufferedReader(new InputStreamReader(in));
 
                  
                   //4.獲取傳輸信息並打印
                   Stringinfo = bufIn.readLine();
                   System.out.println(info);
                  
                   //5.獲取socket的輸出流,寫入信息
                   OutputStreamout = socket.getOutputStream();
                   Stringstr = "服務端:收到信息"+”\r\n”;
                   out.write(str.getBytes());
                  
                  
                   //6.關閉資源
                   socket.close();
                   server.close();
         }
}
 


在使用readLine()一定要確認接收的信息中存在回車或者換行,否則會造成阻塞的情況。

 

練習1:客戶端輸入字母,服務端打印出來,然後把它轉換為大寫字母返回給客戶端。

 

import java.net.*;
import java.io.*;
 
 
class TransClient {
         publicstatic void main(String[] args) throws IOException,UnknownHostException{
                  
                   Sockets = new Socket("127.0.0.1",10001);
                  
                   BufferedReaderbufr = new BufferedReader(new InputStreamReader(System.in));
                  
                   PrintWriterout = new PrintWriter(s.getOutputStream(),true);
                  
                   BufferedReaderbufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
                  
                   Stringline = null;
                  
                   while((line=bufr.readLine())!=null){
                            if("over".equals(line)){
                                     break;
                            }
                            out.println(line);
                            StringupperStr = bufIn.readLine();
                            System.out.println(upperStr);
                   }
                   s.close();
         }
}
 

import java.net.*;
import java.io.*;
 
 
class TransServer {
         publicstatic void main(String[] args) throws IOException,UnknownHostException{
                   ServerSocketss = new ServerSocket(10001);
                  
                   Sockets = ss.accept();
                  
                   Stringip = s.getInetAddress().getHostAddress();
                  
                   System.out.println(ip+"........connected");
                  
                   BufferedReaderbufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
                  
                   PrintWriterout = new PrintWriter(s.getOutputStream(),true);
                  
                   Stringline = null;
                  
                   while((line=bufIn.readLine())!=null){
                            System.out.println(line);
                            out.println(line.toUpperCase());
                   }
                   s.close();
                   ss.close();
         }
        
}
 


練習2:上傳一個文本文件。

 

import java.net.*;
import java.io.*;
 
class TextUploadClient {
        
         publicstatic void main(String[] agrs) throws IOException,SocketException{
                  
                   //1.創建soceket服務
                   Socketclient = new Socket(InetAddress.getLocalHost(),10007);
                  
                   //2.讀取上傳源文件
                   BufferedReaderbr = new BufferedReader(new FileReader("c:\\client.txt"));
                  
                   //3.獲取socket的輸出流
                   OutputStreamout = client.getOutputStream();
                   PrintWriterpw = new PrintWriter(out,true);
                  
                   //4.讀取源文件信息,寫入輸出流。
                   Stringline = null;
                   while((line=br.readLine())!=null){
                            //out.write(line.getBytes());
                            //System.out.println(line);
                            pw.println(line);
                   }
                   client.shutdownOutput();
                   //5.獲取輸入流,讀取服務端的返回信息
                   InputStreamin = client.getInputStream();
                   byte[]buf = new byte[1024];
                   intlen = in.read(buf);
                   Strings = new String(buf,0,len);
                  
                   System.out.println(s);
         }
}


import java.net.*;
import java.io.*;
 
class TextUploadServer {
        
         publicstatic void main(String[] agrs) throws IOException,SocketException{
                  
                   //1.創建soceket服務
                   ServerSocketserver = new ServerSocket(10007);
                  
                   //2.獲取socket對象
                   Socketsocket = server.accept();
                  
                   //3.創建上傳後目的文件
                   Filefile = new File("c:\\server.txt");
                  
                   //4.創建目的文件的輸入流
                   BufferedWriterbw = new BufferedWriter(new FileWriter(file));
                  
                   //5.獲取socket的輸入流
                   BufferedReaderbufIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                  
                   //6.把socket輸入流中信息寫入文件
                   Stringline = null;
                   while((line=bufIn.readLine())!=null){
                            //System.out.println(line);
                            bw.write(line);
                            bw.flush();
                            bw.newLine();
                   }
                  
                  
                   //7.獲取socket的輸出流,返回上傳成功的提示
                   OutputStreamout = socket.getOutputStream();
                   out.write("上傳成功".getBytes());
                  
                   //8.關閉資源
                   bw.close();
                   socket.close();
                   server.close();
                  
         }
}


註意點:上傳文件中的文本通過readLine()讀取到輸入流後,其中文本每一行的回車“\n\r“和文本最後的結束標記不會讀取進去,所以會造成服務端不能換行和readLine()無法結束,需要PrintWriter的println()方法加入換行和給客戶端輸出流加入標記,即socket的shutdownOutput()方法,還有即的緩沖流需要刷新,否則無法及時寫入。


  • URL與URLConnection

 

URL專業術語叫“資源定位符“,意思就是可以指向互聯網的資源,形式其實就是我們常說的網址。 創建URL的對象方法,URL  url = new URL(String s);s就是我們的網址。

URLConnetion是URL調用openConnetion返回的,它其實網絡協議和URL地址的封裝,通過它可以完成對URL資源的讀取和寫入等操作。



值得學習的Blog:

http://blog.csdn.net/ns_code/article/details/14128987

http://www.cnblogs.com/oubo/archive/2012/01/16/2394641.html

http://maxuefeng.blog.51cto.com/1876326/438539



Tags: 網絡編程 Java學習 發送信息 臺式電腦 知識點

文章來源:


ads
ads

相關文章
ads

相關文章

ad