原文來自搬磚工,如需轉載請注明出處
這篇文章簡單總結1下java網絡編程的相干知識
1、TCP和UDP
1.TCP(傳輸控制協議)方式
TCP方式就類似于撥打電話,使用該種方式進行網絡通訊時,需要建立專門的虛擬連接,然落后行可靠的數據傳輸,如果數據發送失敗,則客戶端會自動重發該數據
2. UDP(用戶數據報協議)方式
UDP方式就類似于發送短信,使用這類方式進行網絡通訊時,不需要建立專門的虛擬連接,傳輸也不是很可靠,如果發送失敗則客戶端沒法取得
這兩種傳輸方式都是實際的網絡編程中進行使用,重要的數據1般使用TCP方式進行數據傳輸,而大量的非核心數據則都通過UDP方式進行傳遞,在1些程序中乃至結合使用這兩種方式進行數據的傳遞。由于TCP需要建立專用的虛擬連接和確認傳輸是不是正確,所以使用TCP方式的速度略微慢1些,而且傳輸時產生的數據量要比UDP略微大1些。
總結1下UDP和TCP協議的區分
–使用UDP時,每一個數據報中都給出了完全的地址信息,因此無需要建立發送方和接收方的連接。
–對TCP協議,由于它是1個面向連接的協議,在socket之間進行數據傳輸之前必定要建立連接,所以在TCP中多了1個連接建立的時間
–使用UDP傳輸數據時是有大小限制的,每一個被傳輸的數據報必須限定在64KB以內。
–TCP沒有這方面的限制,1旦連接建立起來,雙方的socket就能夠按統1的格式傳輸大量的數據。
–UDP是1個不可靠的協議,發送方所發送的數據報其實不1定以相同的次序到達接收方。
–TCP是1個可靠的協議,它確保接收方完全正確地獲得發送方所發送的全部數據
–TCP在網絡通訊上有極強的生命力,例如遠程連接(Telnet)和文件傳輸(FTP)都需要不定長度的數據被可靠地傳輸。
–相比之下UDP操作簡單,而且僅需要較少的監護,因此通經常使用于局域網高可靠性的分散系統中client/server利用程序
2、基于URL的網絡編程
1.創建1個URL
為了表示URL, java.NET中實現了類URL。我們可以通過下面的構造方法來初始化1個URL對象:
(1)public URL (String spec);
通過1個表示URL地址的字符串可以構造1個URL對象
URL urlBase=new URL("http://www. 263.Net/")
(2)public URL(URL context, String spec);
通過基URL和相對URL構造1個URL對象。
URL net263=new URL ("http://www.263.net/");
URL index263=new URL(net263, "index.html")
(3)public URL(String protocol, String host, String file);
new URL("http", "www.gamelan.com", "/pages/Gamelan.net. html");
(4)public URL(String protocol, String host, int port, String file);
URL gamelan=new URL("http", "www.gamelan.com", 80, "Pages/Gamelan.network.html");
注意:類URL的構造方法都聲明拋棄非運行時例外(MalformedURLException),因此生成URL對象時,我們必須要對這1例外進行處理,通常是用try-catch語句進行捕獲。格式以下:
try{ URL myURL= new URL(…) }catch (MalformedURLException e){ … }2. 解析1個URL
public String getProtocol() 獲得該URL的協議名。 public String getHost() 獲得該URL的主機名。 public int getPort() 獲得該URL的端口號,如果沒有設置端口,返回⑴。 public String getFile() 獲得該URL的文件名。 public String getRef() 獲得該URL在文件中的相對位置。 public String getQuery() 獲得該URL的查詢信息。 public String getPath() 獲得該URL的路徑 public String getAuthority() 獲得該URL的權限信息 public String getUserInfo() 取得使用者的信息 public String getRef()取得該URL的錨3.從URL讀取WWW網絡資源
URL url = new URL("http://www.baidu.com"); //使用openStream得到1輸入流并由此構造1個BufferedReader對象 BufferedReader br = new BufferedReader(new InputStreamReader( url.openStream())); String line = null; while(null != (line = br.readLine())) { System.out.println(line); } br.close();3、客戶端網絡編程步驟
4、InetAddress
該類的功能是代表1個IP地址,并且將IP地址和域名相干的操作方法包括在該類的內部。
關于該類的使用,下面通過1個基礎的代碼示例演示該類的使用,代碼以下:
import java.net.InetAddress; public class InetAddressDemo { public static void main(String[] args) { try { // 使用域名創建對象 InetAddress inet1 = InetAddress.getByName("www.163.com"); System.out.println(inet1); // 使用IP創建對象 InetAddress inet2 = InetAddress.getByName("127.0.0.1"); System.out.println(inet2); // 取得本機地址對象 InetAddress inet3 = InetAddress.getLocalHost(); System.out.println(inet3); // 取得對象中存儲的域名 String host = inet3.getHostName(); System.out.println("域名:" + host); // 取得對象中存儲的IP String ip = inet3.getHostAddress(); System.out.println("IP:" + ip); } catch (Exception e) { } } }注:InetAddress 類沒有明顯的構造函數。為生成1個InetAddress對象,必須應用1個可用的工廠方法。
5、TCP編程
在Java語言中,對TCP方式的網絡編程提供了良好的支持,在實際實現時,以java.net.Socket類代表客戶端連接,以java.net.ServerSocket類代表服務器端連接。在進行網絡編程時,底層網絡通訊的細節已實現了比較高的封裝,所以在程序員實際編程時,只需要指定IP地址和端口號碼就能夠建立連接了。
在客戶端網絡編程中,首先需要建立連接,在Java API中以java.net.Socket類的對象代表網絡連接
客戶端
1) 建立Socket連接
Socket socket2 = new Socket(“www.sohu.com”,80);
2)依照“要求-響應”模型進行網絡數據交換
在Java語言中,數據傳輸功能由Java IO實現,也就是說只需要從連接中取得輸入流和輸出流便可,然后將需要發送的數據寫入連接對象的輸出流中,在發送完成以后從輸入流中讀取數據便可。示例代碼以下:
OutputStream os = socket1.getOutputStream(); //取得輸出流
InputStream is = socket1.getInputStream(); //取得輸入流
這里取得的只是最基本的輸出流和輸入流對象,還可以根據前面學習到的IO知識,使用流的嵌套將這些取得到的基本流對象轉換成需要的裝潢流對象,從而方便數據的操作。
3)關閉網絡連接
socket1.close();
服務器端
首先需要說明的是,客戶真個步驟和服務器真個編寫步驟不同,所以在學習服務器端編程時注意不要和客戶端混淆起來。
1)監聽端口
ServerSocket ss = new ServerSocket(10000);
2)取得連接
當有客戶端連接到達時,建立1個和客戶端連接對應的Socket連 接對象,從而釋放客戶端連接對服務器端端口的占用
Socket socket = ss.accept();
該代碼實現的功能是取得當前連接到服務器真個客戶端連接。需要說明的是accept和前面IO部份介紹的read方法1樣,都是1個阻塞方法,也就是當無連接時,該方法將阻塞程序的履行,直到連接到達時才履行該行代碼。另外取得的連接會在服務器真個該端口注冊,這樣以后就能夠通過在服務器真個注冊信息直接通訊,而注冊以后服務器真個端口就被釋放出來,又可以繼續接受其它的連接了。
3)依照“要求-響應”模型進行網絡數據交換
這里取得的Socket類型的連接就和客戶真個網絡連接1樣了,只是服務器端需要首先讀取發送過來的數據,然落后行邏輯處理以后再發送給客戶端,也就是交換數據的順序和客戶端交換數據的步驟恰好相反
InputStream is = ss.getInputStream(); //取得輸入流
OutputStream os = ss.getOutputStream(); //取得輸出流
4)關閉服務器端連接
ss.close();
以上就是基本的TCP類型的服務器和客戶端代碼實現的步驟,下面以1個簡單的echo(回聲)服務實現為例子,介紹綜合使用示例,實現的代碼以下:
import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Constants { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; OutputStream os = null; InputStream is = null; // 監聽端口號 int port = 10000; try { // 建立連接 serverSocket = new ServerSocket(port); // 取得連接 socket = serverSocket.accept(); // 接收客戶端發送內容 is = socket.getInputStream(); byte[] b = new byte[1024]; int n = is.read(b); // 輸出 System.out.println("客戶端發送內容為:" + new String(b, 0, n)); // 向客戶端發送反饋內容 os = socket.getOutputStream(); os.write(b, 0, n); } catch (Exception e) { e.printStackTrace(); } finally { try { // 關閉流和連接 os.close(); is.close(); socket.close(); serverSocket.close(); } catch (Exception e) { } } } }6、UDP編程
UDP(User Datagram Protocol),中文意思是用戶數據報協議使用該種方式無需建立專用的虛擬連接,由于無需建立專用的連接,所以對服務器的壓力要比TCP小很多,所以也是1種常見的網絡編程方式。但是使用該種方式最大的不足是傳輸不可靠,固然也不是說常常丟失,就像大家發短信息1樣,理論上存在收不到的可能
在Java API中,實現UDP方式的編程,包括客戶端網絡編程和服務器端網絡編程,主要由兩個類實現,分別是:
l DatagramSocket
DatagramSocket類實現“網絡連接”,包括客戶端網絡連接和服務器端網絡連接。雖然UDP方式的網絡通訊不需要建立專用的網絡連接,但是畢竟還是需要發送和接收數據,DatagramSocket實現的就是發送數據時的發射器,和接收數據時的監聽器的角色。類比于TCP中的網絡連接,該類既可以用于實現客戶端連接,也能夠用于實現服務器端連接。
l DatagramPacket
DatagramPacket類實現對網絡中傳輸的數據封裝,也就是說,該類的對象代表網絡中交換的數據。在UDP方式的網絡編程中,不管是需要發送的數據還是需要接收的數據,都必須被處理成DatagramPacket類型的對象,該對象中包括發送到的地址、發送到的端口號和發送的內容等。其實DatagramPacket類的作用類似于現實中的信件,在信件中包括信件發送到的地址和接收人,還有發送的內容等,郵局只需要依照地址傳遞便可。在接收數據時,接收到的數據也必須被處理成DatagramPacket類型的對象,在該對象中包括發送方的地址、端口號等信息,也包括數據的內容。和TCP方式的網絡傳輸相比,IO編程在UDP方式的網絡編程中變得不是必須的內容,結構也要比TCP方式的網絡編程簡單1些。
UDP客戶端編程觸及的步驟也是4個部份:建立連接、發送數據、接收數據和關閉連接。
1)建立連接:
DatagramSocket ds = new DatagramSocket();
該客戶端連接使用系統隨機分配的1個本地計算機的未用端口號
固然,可以通過制定連接使用的端口號來創建客戶端連接。
DatagramSocket ds = new DatagramSocket(5000);
1般在建立客戶端連接時沒有必要指定端口號碼。
2)發送數據
在發送數據時,需要將需要發送的數據內容首先轉換為byte數組,然后將數據內容、服務器IP和服務器端口號1起構造成1個DatagramPacket類型的對象,這樣數據的準備就完成了了,發送時調用網絡連接對象中的send方法發送該對象便可
代碼示例:
String s = "Hello"; String host = "127.0.0.1"; int port = 10001; //將發送的內容轉換為byte數組 byte[] b = s.getBytes(); //將服務器IP轉換為InetAddress對象 InetAddress server = InetAddress.getByName(host); //構造發送的數據包對象 DatagramPacket sendDp = new DatagramPacket(b,b.length,server,port); //發送數據 ds.send(sendDp);在該示例代碼中,不管發送的數據內容是甚么,都需要轉換為byte數組,然后將服務器真個IP地址構造成InetAddress類型的對象,在準備完成以后,將這些信息構造成1個DatagramPacket類型的對象,在UDP編程中,發送的數據內容、服務器真個IP和端口號,都包括在DatagramPacket對象中。在準備完成以后,調用連接對象ds的send方法把DatagramPacket對象發送出去便可。
//構造緩沖數組 byte[] data = new byte[1024]; //構造數據包對象 DatagramPacket receiveDp = new DatagramPacket(data,data.length); //接收數據 ds.receive(receiveDp); //輸出數據內容 byte[] b = receiveDp.getData(); //取得緩沖數組 int len = receiveDp.getLength(); //取得有效數據長度 String s = new String(b,0,len); System.out.println(s);代碼講授 :首先構造緩沖數組data,這里設置的長度1024是預估的接收到的數據長度,要求該長度必須大于或等于接收到的數據長度,然后以該緩沖數組為基礎,構造數據包對象,使用連接對象ds的receive方法接收反饋數據,由于在Java語言中,除String之外的其它對象都是依照地址傳遞,所以在receive方法內部可以改變數據包對象receiveDp的內容,這里的receiveDp的功能和返回值類似。數據接收到以后,只需要從數據包對象中讀取出來就能夠了,使用DatagramPacket對象中的getData方法可以取得數據包對象的緩沖區數組,但是緩沖區數組的長度1般大于有效數據的長度,換句話說,也就是緩沖區數組中只有1部份數據是反饋數據,所以需要使用DatagramPacket對象中的getLength方法取得有效數據的長度,則有效數據就是緩沖數組中的前有效數據長度個內容,這些才是真實的服務器端反饋的數據的內容
//取得客戶真個IP InetAddress clientIP = receiveDp.getAddress(); //取得客戶真個端口號 Int clientPort = receiveDp.getPort();3)關閉連接
ps:總結的不是很全面,但很基礎,應當合適初學者學習,由于本人也是初學者的小菜鳥,所有很多東西可能都觸及不到,希望大家見諒!