Java 網路程式設計 Java中的網路程式設計
說道網路程式設計,瞭解socket程式設計,分為TCP和UPD,對於具體實現細節,就不知道。希望學完這一塊,自己能夠獨立完成一個socket的編寫。
關於網際網路WEB相關的知識點,後面開始總結,今天不在此作介紹。
Socket套接字:網路上具有唯一標識的IP地址和埠組合在一起才能構成唯一能識別的識別符號套接字。
Socket原理機制:
通訊的兩端都有Socket,網路通訊其實就是Socket間的通訊,資料在兩個Socket間通過IO傳輸。
Java中的網路支援:針對網路通訊的不同層次,Java提供了不同的API,其提供的網路功能有四大類:
InetAddress:用於標識網路上的硬體資源,主要是IP地址
URL:統一資源定位符,通過URL可以直接讀取或寫入網路上的資料。
Sockets:使用TCP協議實現的網路通訊Socket相關的類
Datagram:使用UPD協議,將資料儲存在使用者資料中,通過網路進行通訊。
1:InetAddress
標識網路上的硬體資源,沒有構造方法(預設都沒有),標識網際網路協議IP地址
1 package lesson1220Socket; 2 3 import java.net.InetAddress; 4 import java.net.UnknownHostException; 5 6 public class InetAddressDemo {7 8 public static void main(String[] args) throws UnknownHostException { 9 InetAddress address = InetAddress.getLocalHost(); 10 11 //InetAddress ad = new InetAddress(); The constructor InetAddress() is not visible 12 13 byte [] by = address.getAddress(); //實際上裡面存的值是[100, 98, 60, 87]14 System.out.println(by); 15 System.out.println(address.getHostAddress()); 16 System.out.println(address.getHostName()); 17 return; 18 } 19 }
執行結果:
[[email protected]
100.98.60.87
CN00204505
2、URL類
統一資源定位符,標識Internet上某一資源的地址,
Java中的網路程式設計
Java中的網路程式設計主要是Java的Socket程式設計,屬於JavaEE中的高階的部分,以下內容是對java網路程式設計的一個小結,程式碼都是經過編譯除錯的
C/S程式應用:客戶/伺服器模式,如QQ客戶端,客戶端連到伺服器上,一個C/S模式的應用必須有兩套程式,一個是客戶端的程式,一個是伺服器程式。
B/S程式應用:瀏覽器/伺服器模式,如當下的各種網站都是B/S模式,所有的程式程式碼都在伺服器上,使用者通過瀏覽器去訪問。
C/S程式分為兩種:
基於TCP協議:Socket(套接字), 可靠的程式設計: A->B 如打電話先建立連線
基於UDP協議:不可靠,如簡訊功能。
如果編寫一個TCP程式需要JAVA的兩個包支援:
java.net.*: 主要提供網路支援;
|-ServerSocket類:伺服器端程式
|-Socket類:客戶端程式
java,io.*:傳遞資訊流
3、TCP程式設計
TCP協議是面向連線的、可靠的、有序的、以位元組流的方式傳送資料。通過三次握手方式建立連線。形成傳輸資料的通道。在連線中進行大量資料的傳輸,效率會稍低。
Java中基於TCP協議實現網路通訊的類:客戶端是Socket, 伺服器端是ServerSocket。
看上面圖,可以看出Socket通訊步驟:建立ServerSocket和Socket,開啟連線到Socket的輸入輸出流,按照協議對Socket進行讀寫操作,關閉輸入輸出流,關閉Socket。
3.1 伺服器端:
a:建立ServerScoket,並繫結埠
b:呼叫accept()開始監聽埠
c:建立連線後,通過輸入流獲取客戶端傳送的請求資訊
d:通過輸出流向客戶端返回響應資訊
e:關閉Socket等相關資源
3.2 客戶端:
a:建立Socket,並指定需要連線的伺服器的IP和埠
b:建立連線後,通過輸出流向伺服器端傳送資訊
c:通過輸入流獲取伺服器返回的響應資訊
d:關閉Socket等資源
例子如下:
1 package lesson1220Socket; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.ServerSocket; 10 import java.net.Socket; 11 12 import com.sun.org.apache.xalan.internal.xsltc.trax.OutputSettings; 13 14 //基於TCP/IP協議的Socket,使用者實現登入伺服器端 15 public class ServeSocketDemo { 16 public static void main(String[] args) throws Exception { 17 18 //1、建立一個ServerSocket服務端,指定繫結的埠,並監聽埠 19 ServerSocket ss = new ServerSocket(10086); //1024-65535的某個值 20 System.out.println("伺服器端開始監聽10086埠....."); 21 //2、呼叫accept方法開始監聽埠 22 Socket socket = ss.accept(); 23 24 //3、獲取輸入流,並讀取客戶端資訊 25 InputStream is = socket.getInputStream(); 26 InputStreamReader isr = new InputStreamReader(is); //InputStreamReader 27 BufferedReader br = new BufferedReader(isr); 28 29 String info = null; 30 while((info = br.readLine())!=null){ 31 System.out.println("我是伺服器,客戶端說:"+info); 32 } 33 socket.shutdownInput(); 34 35 //4、獲取輸出流,響應客戶端請求 36 OutputStream os = socket.getOutputStream(); 37 PrintWriter pw = new PrintWriter(os); 38 pw.write("歡迎您"); 39 pw.flush(); 40 System.out.println("給客戶端迴響應....."); 41 42 //5、關閉資源 43 pw.close(); 44 os.close(); 45 br.close(); 46 isr.close(); 47 is.close(); 48 socket.close(); 49 ss.close(); 50 51 } 52 53 } 54 55 56 package lesson1220Socket; 57 58 import java.io.BufferedReader; 59 import java.io.IOException; 60 import java.io.InputStream; 61 import java.io.InputStreamReader; 62 import java.io.OutputStream; 63 import java.io.PrintWriter; 64 import java.net.Socket; 65 import java.net.UnknownHostException; 66 67 public class ClientSocketDemo { 68 69 public static void main(String[] args) throws UnknownHostException, IOException { 70 //1、建立客戶端Socket,指定伺服器和埠 71 Socket cs = new Socket("127.0.0.1", 10086); 72 System.out.println("與服務端建立連線....."); 73 74 //2、獲取輸出流,向伺服器傳送資訊 75 OutputStream os = cs.getOutputStream();//直接輸出流 76 PrintWriter pw = new PrintWriter(os); 77 pw.write("使用者名稱:admin,密碼:123"); 78 pw.flush(); 79 cs.shutdownOutput(); 80 System.out.println("向服務端傳送資訊....."); 81 82 //3、獲取輸入流,得到伺服器響應資訊 83 InputStream is = cs.getInputStream(); 84 InputStreamReader isr = new InputStreamReader(is); 85 BufferedReader br = new BufferedReader(isr); 86 String info; 87 while((info = br.readLine())!=null){ 88 System.out.println("我是客戶端,服務端響應資訊:"+info); 89 } 90 91 //4、關閉資源 92 br.close(); 93 isr.close(); 94 is.close(); 95 pw.close(); 96 os.close(); 97 cs.close(); 98 99 } 100 101 }
上面先執行服務端:ServeSocketDemo,再啟動客戶端:ClientSocketDemo
執行結果如下:
ServeSocketDemo:
伺服器端開始監聽10086埠.....
我是伺服器,客戶端說:使用者名稱:admin,密碼:123
給客戶端迴響應.....
ClientSocketDemo:
與服務端建立連線.....
向服務端傳送資訊.....
我是客戶端,服務端響應資訊:歡迎您
4、UDP程式設計
前面介紹的Socket程式設計都是基於TCP/IP協議的,現在來看一下基於UDP協議程式設計。
UPD協議(使用者資料報協議)是無連線的、不可靠的、無序的,速度快。進行資料傳輸時,首先將要傳輸的資料定義成資料報(Datagram),大小限制在64k,在資料報中指明資料索要達到的Socket(主機地址和埠號),然後再將資料報傳送出去。UDP協議的主要作用就是完成網路資料流和資料包之間的轉換-------在資訊傳送端,UDP協議將網路資料流封裝到資料報,然後被資料報傳送出去;在資訊接收端,UDP協議將資料報轉換成實際資料內容。
1>首先在UDP網路程式設計中沒有伺服器和客戶端這種說法,兩個Socket之間沒有虛擬鏈路。只是接收和傳送報文
2>這裡面有兩個重要的類:DatagramSocket和DatagramPacket.
DatagramSocket的兩個建構函式:
public DatagramSocket():構造資料報套接字並將其繫結到本地主機上任何可用的埠。
public DatagramSocket(int port):建立資料報套接字並將其繫結到本地主機上的指定埠。
在我們下面的DEMO中,UDPServerTest類中先發送資料報,使用的是套接字的無參構造器,而UDPClientTest類中先接收資料報,必須監聽某一個埠,所以使用的是套接字的有參構造器。
DatagramPacket的建構函式:
public DatagramPacket(byte buf[], int length):用來接收長度為length的資料包
public DatagramPacket(byte buf[], int length, InetAddress address, int port):用來將長度為length的包傳送到指定主機上的指定埠號。
package lesson1220Socket; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; public class UDPServer2 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(); String str = "hello world"; //構造用於傳送的資料包,指定主機和埠號 DatagramPacket packet = new DatagramPacket(str.getBytes(), str.length(), InetAddress.getByName("localhost"), 5555); ds.send(packet); //讀取從客戶端傳送過來的響應 byte[] buffer = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(buffer,buffer.length); ds.receive(packet2); System.out.println("address: " + packet2.getAddress() + " port: "+ packet2.getPort()); String str2 = new String(buffer,0,packet2.getLength()); System.out.println(str2); ds.close(); } } package lesson1220Socket; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UDPClient2 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(5555); byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); ds.receive(packet); System.out.println("address: " + packet.getAddress() + " port: "+ packet.getPort()); String str = new String(buffer, 0, packet.getLength()); System.out.println(str); // 接收到資料包之後,客戶端返回響應回去 String str2 = "welcome"; DatagramPacket packet2 = new DatagramPacket(str2.getBytes(), str2 .length(), packet.getAddress(), packet.getPort()); ds.send(packet2); ds.close(); } }
上面的例子,要先執行UDPClient2(接收端先啟動) ,然後再執行UDPServer2 ,
執行結果如下:
UDPServer2:
address: /127.0.0.1 port: 5555
welcome
UDPClient2:
address: /127.0.0.1 port: 54071
hello world
1、上面的程式中,第一步是伺服器端(暫且以這種叫法來區分這兩個類)建立一個UDP套接字,沒有指定埠,使用的是系統分配的埠。然後構建了一個數據包,包中指定 了目標機器的ip和埠號。
2、作為客戶端,建立了一個UDP套接字,並且綁定了埠,如果想要接收到服務端傳送過來的報文,繫結的埠必須和伺服器端傳送的包中指定的埠一致。
3、客戶端列印了包中的內容之後,想要返回一些內容回去。這個時候,伺服器端的ip和埠號可以從之前傳送過來的資料包中獲取。
DatagramPacket packet2 = new DatagramPacket(str2.getBytes(), str2.length(), packet.getAddress(), packet.getPort());
4、在伺服器接收資料包的時候,已經不需要再像客戶端建立套接字一樣去繫結埠了,因為目前監聽的埠和客戶端傳送的包中指定的埠是一樣的。
5、列印看下伺服器端的ip和監聽的埠號:(注意理解下這個地方埠號,不是5555)
serverIp =/127.0.0.1;serverPort=54071
6、其中DatagramSocket的receive(DatagramPacket p)方法在接收到資料包前一直阻塞。
看下面這個例子:各自互動三次:
1 package lesson1220Socket; 2 3 import java.net.DatagramPacket; 4 import java.net.DatagramSocket; 5 import java.net.InetAddress; 6 import java.net.SocketException; 7 8 public class UDPServer { 9 10 public static void main(String[] args) throws Exception { 11 //1:建立伺服器端Socket,指定埠 12 DatagramSocket ds = new DatagramSocket(8888); 13 //2、建立資料報,用於接收客戶端傳送的資訊 14 byte [] data = new byte[1024]; 15 DatagramPacket dp = new DatagramPacket(data, data.length); 16 //3、接收客戶端傳送的資料 17 System.out.println("開始接收資料1111!"); 18 ds.receive(dp); 19 20 //4、讀取資料 21 String info = new String(data, 0, dp.getLength()); 22 System.out.println("我是服務端,收到客戶端的資訊是: "+info); 23 24 25 //5、像客戶端響應資料 26 //定義客戶端的地址、埠號和資料 27 InetAddress ia = dp.getAddress(); 28 int port = dp.getPort(); 29 System.out.println("dp ia: " + ia + " port: " + port); 30 //組裝傳送資料報 31 byte []data2 = "你好客戶端!".getBytes(); 32 DatagramPacket dp2 = new DatagramPacket(data2, data2.length, ia, port); 33 //響應客戶端 34 System.out.println("開始傳送資料2222!"); 35 ds.send(dp2); 36 37 38 //6、接收客戶端第二次傳送的資料 39 System.out.println("開始接受資料3333!"); 40 ds.receive(dp); 41 System.out.println("dp ia: " + dp.getAddress() + " port: " + dp.getPort()); 42 43 //7、讀取資料 44 info = new String(data, 0, dp.getLength()); 45 System.out.println("我是服務端,收到第二次客戶端的資訊是: "+info); 46 47 48 ds.close(); 49 } 50 51 } 52 53 package lesson1220Socket; 54 55 import java.io.IOException; 56 import java.net.DatagramPacket; 57 import java.net.DatagramSocket; 58 import java.net.InetAddress; 59 import java.net.SocketException; 60 61 import sun.io.ByteToCharCp1006; 62 63 public class UDPClient { 64 65 public static void main(String[] args) throws Exception { 66 67 InetAddress ia = InetAddress.getLocalHost(); 68 69 //1:建立客戶端端Socket,指定埠和地址 70 DatagramSocket ds = new DatagramSocket(); 71 //2、建立資料報,用於向伺服器端傳送資訊 72 byte [] data = "服務端你好".getBytes(); 73 DatagramPacket dp = new DatagramPacket(data, data.length, ia, 8888); 74 //3、向伺服器端傳送資料 75 System.out.println("A開始傳送資料1111!"); 76 ds.send(dp); 77 78 79 //4、讀取資料 80 byte [] data2 = new byte[1024]; 81 DatagramPacket dp2 = new DatagramPacket(data2, data2.length); 82 System.out.println("A開始接收資料2222!"); 83 ds.receive(dp2); 84 85 System.out.println("dp2 ia: " + dp2.getAddress() + " port: " + dp2.getPort()); 86 String info = new String(data2, 0, dp2.getLength()); 87 System.out.println("我是客戶端,伺服器回的資訊是: "+info); 88 89 //5、第二次傳送資料 90 DatagramPacket dp3 = new DatagramPacket(data, data.length, dp2.getAddress(), dp2.getPort()); 91 System.out.println("A開始傳送資料3333!"); 92 ds.send(dp3); 93 94 ds.close(); 95 96 } 97 98 }
上面這個程式先執行UDPServer, 再執行UDPClient。
執行結果:
UDPServer:
開始接收資料1111!
我是服務端,收到客戶端的資訊是: 服務端你好
dp ia: /100.98.19.103 port: 56013
開始傳送資料2222!
開始接受資料3333!
dp ia: /100.98.19.103 port: 56013
我是服務端,收到第二次客戶端的資訊是: 服務端你好
UDPClient:
A開始傳送資料1111!
A開始接收資料2222!
dp2 ia: /100.98.19.103 port: 8888
我是客戶端,伺服器回的資訊是: 你好客戶端!
A開始傳送資料3333!
參考帖子:
https://www.cnblogs.com/dongguacai/p/5747603.html
https://www.cnblogs.com/dongguacai/p/5747397.html
https://www.cnblogs.com/rocomp/p/4790340.html-------基礎講解
https://www.cnblogs.com/Qian123/tag/java%E5%9F%BA%E7%A1%80/default.html?page=3
https://www.cnblogs.com/yiwangzhibujian/p/7107785.html
https://blog.csdn.net/facekbook/article/details/55506347
其他基礎:
https://blog.csdn.net/hguisu/article/category/1122753
https://www.cnblogs.com/dolphin0520/category/602384.html
關於TCP/IP中更多的例子請看另一篇關於Socket多執行緒程式設計!