多數情況下,我們的程式是需要同外界通信的,Java中如果我們想要讓程式去進行通信,就要用到java.net包下的幾個類。在說這幾個類之前,我們先大體了解幾組概念。
通信有三要素,分别是IP,端口以及通信協定。
IP位址 ,可以認為是每台主機的位址,通過這個位址我們就可以找到要通信的主機在哪了。端口号也就是程序的位址,隻找到主機我們還是不能通信,我們還需要找到要通信的程序。當主機跟程序都找到之後,我們還需要有一定的傳輸資料的規範,那麼這個規範就是我們所說的傳輸協定了。我們主要用到的傳輸協定有兩種:UDP協定和TCP協定。
UDP:對資料封裝,打包,不需建立連接配接;直接把資料扔過去,每個資料報限制大小在64K,不可靠協定,但速度快。
TCP:先建立連接配接,形成傳輸資料的通道,通過三次握手完成連接配接之後才能傳輸資料,是可靠協定,效率低。分為用戶端和服務端0
一、InetAddress類
此類表示網際網路協定 (IP) 位址。有兩個子類Inet4Address,Inet6Address,分别代表兩種IP位址的結構。IP協定使用的IP 位址是32 位或 128 位無符号數字,它是一種低級協定,UDP 和 TCP 協定都是在它的基礎上建構的。
InetAddress沒有構造方法,是以我們要通過靜态方法來擷取該類的對象,這裡使用的方法是:
static InetAddress getByName(String host) 在給定主機名或Ip的情況下确定主機的 IP 位址。其中host參數可以是本地主機的名字,可以是一個IP位址,也可以是個域名。還有一種擷取本地主機Ip的方式,使用 static InetAddress getLocalHost() 。
該類還有幾個常用的方法:
String getHostAddress() : 傳回 IP 位址字元串(以文本表現形式)。
String getHostName() : 擷取此 IP 位址的主機名。
static InetAddress getLocalHost(): 傳回本地主機,可以用來建立本地主機的InetAddress對象。
private static void method() throws UnknownHostException {
//傳本地主機名參數
InetAddress address = InetAddress.getByName("七寶");
System.out.println(address);
//output: 七寶/172.17.31.30
System.out.println(address.getHostAddress());
System.out.println(address.getHostName());
//output:172.17.31.30
// 七寶
//傳一個IP參數
InetAddress address2 = InetAddress.getByName("172.17.31.30");
System.out.println(address2);
//output: /172.17.31.30
System.out.println(address2.getHostAddress());
System.out.println(address2.getHostName());
//output:172.17.31.30
// 172.17.31.30
//獲得本地主機名
InetAddress address3 = InetAddress.getLocalHost();
System.out.println(address3);
//output:七寶/172.17.31.30
System.out.println(address3.getHostAddress());
System.out.println(address3.getHostName());
//output:172.17.31.30
// 七寶
//傳一個域名參數
InetAddress address4 = InetAddress.getByName("www.cn.bing.com");
System.out.println(address4);
//output:www.cn.bing.com/204.79.197.200
System.out.println(address4.getHostAddress());
System.out.println(address4.getHostName());
//output:204.79.197.200
// www.cn.bing.com
//傳bing的IP作參數
InetAddress address5 = InetAddress.getByName("204.79.197.200");
System.out.println(address5);
//output:/204.79.197.200
System.out.println(address5.getHostAddress());
System.out.println(address5.getHostName());
//output:204.79.197.200
// a-0001.a-msedge.net
}
二、使用UDP協定發送接收資料
利用Socket開發網絡程式設計已成為主流,不論是使用UDP還是TCP,我們都将用到Socket。在使用UDP傳輸資料時,我們需要對資料進行封裝,打包。需要用到DatagramSocket類和DatagramPacket類。
java.net.DatagramSocket:此類表示用來發送和接收資料報包的套接字,基于UDP協定。
DatagramSocket() :建立Socket對象并随機配置設定端口号,用于發送端。
DatagramSocket(int port):建立Socket對象并指定端口号port,用于接收端。
java.net.DatagramPacket:此類表示資料報包,資料包大小需要小于64K。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) :構造資料報包,用來将buf數組中從offset開始,長度為 length 的内容打包發送到指定主機上的指定端口号。
DatagramPacket(byte[] buf, int length):構造 DatagramPacket,用來接收長度為 length 的資料包。
使用UPD協定發送資料的步驟
1. 建立發送端Socket對象
2. 建立資料并打包
3. 發送資料包
4. 釋放資源
用到的方法:
除構造方法外,使用DatagramSocket類中的void send(DatagramPacket p) :從此套接字發送資料報包。
public class SendByUDP {
public static void main(String[] args) throws IOException {
// 建立Socket對象
DatagramSocket ds = new DatagramSocket();
/* 建立資料并打包 */
// 建立資料
String s ="hello upd~~~~~~~~~~~~~~";
byte[] bys = s.getBytes();
int length = bys.length;
InetAddress address = InetAddress.getByName("七寶");
int port = 8888;
// 建立資料包
DatagramPacket p = new DatagramPacket(bys,0,length,address,port);
// 發送資料
ds.send(p);
// 釋放資源
ds.close();
}
}
使用UPD協定接收資料的步驟
1. 建立接收端Socket對象
2. 接收資料
3. 解析資料
4. 處理資料
5. 釋放資源
用到的方法:
DatagramSocket類中的void receive(DatagramPacket p)接收資料
InetAddress getAddress() :擷取發送端的IP對象
byte[] getData() :擷取接收到的資料,也可直接使用建立包對象時的數組
int getLength() :擷取接收到的資料的長度。
public class ReceiveByUDP {
public static void main(String[] args) throws IOException {
// 建立接收端Socket對象,需要指定端口
DatagramSocket ds = new DatagramSocket(8888);
// 建立接收資料報包
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
//接收資料
ds.receive(dp);//阻塞
// 解析資料
InetAddress address = dp.getAddress();
byte[] data = dp.getData();
int length = dp.getLength();
// 處理資料,可以用資料段的getData方法擷取的
System.out.println("sender:"+ address.getHostAddress()+"---->"+ new String(data,0,length));
// 也可以用接收資料時,資料包中存放的數組
System.out.println("sender:"+ address.getHostAddress()+"---->"+ new String(buf,0,length));
// 釋放資源
ds.close();
}
}
三、使用TCP協定發送接收資料
與UDP不同,我們在使用TCP進行通信時,用到的套接字是Socket和ServerSocket
java.net.Socket:此類實作用戶端(發送端)套接字。套接字是兩台機器間通信的端點。
java.net.ServerSocket:此類實作伺服器(接收端)套接字。伺服器套接字等待請求通過網絡傳入。
用戶端發送資料給服務端的步驟
1. 建立用戶端Socket對象(建立連接配接,需要指明Ip和port端口号)
2. 基于Socket建立輸出流對象(發送資料的管道)
3. 發送資料(以位元組的形式發送)
4. 釋放資源
用到的幾個方法:
構造函數 Socket(InetAddress address, int port) :建立一個流套接字并将其連接配接到指定 IP 位址的指定端口号
Socket類中擷取輸出流的方法 OutputStream getOutputStream() :傳回此套接字的輸出流。
輸出流 OutputStream的 write() 方法,此方法用來發送資料,即将資料寫入服務端。
public class SendByTCP {
public static void main(String[] args) throws IOException {
// 建立Socket對象(建立連接配接,需要Ip和port,此處是與本地進行通信)
Socket s = new Socket(InetAddress.getByName("七寶"), 80);
// 基于Socket建立輸出流對象(發送資料的管道)
OutputStream os = s.getOutputStream();
// 發送資料,注意要使用位元組流發送
os.write("hello ,tcp. im coming.".getBytes());
// 釋放資源
os.close();
s.close();
}
}
非常簡短的幾行代碼,我們就可以把一個簡易用戶端要做的事情寫完了,接下來我們再來看服務端如何接收這些資料。
服務端接收來自用戶端資料的步驟
1. 建立服務端ServerSocket對象
2. 監聽(阻塞),用戶端有連接配接時,建立連接配接
3. 建立輸入流對象(管道)
4. 接收資料
5. 輸出資料
6. 釋放資源(服務端Socket一般不用關閉)
用到的幾個方法:
構造函數ServerSocket(int port) :建立綁定到特定端口的伺服器套接字。
傳回Socket對象的ServerSocket方法 Socket accept() :監聽并接收到此套接字的連接配接。
Socket類中擷取輸入流的方法 InputStream getInputStream() :傳回此套接字的輸出流。
輸入流 InputStream的 read() 方法,此方法用來接收資料,即輸入流來讀取資料。
Socket類中的 getInetAddress()方法,此方法用來擷取發送端IP。
public class ReceiveByTCP {
public static void main(String[] args) throws IOException {
// 建立Socket對象,端口号要與發送端設定的一緻
ServerSocket ss = new ServerSocket(80);
// 監聽(阻塞)
Socket s = ss.accept();
// 建立輸入流對象(管道)
InputStream is = s.getInputStream();
// 接收資料,當資料量大時,我們需要用到循環
byte[] bys = new byte[1024];
int len;
len = is.read(bys);
// 輸出資料,調用Socket的getInetAddress方法可獲得IP對象
InetAddress inetAddress = s.getInetAddress();
System.out.println("sender:" + inetAddress.getHostName() + "====>");
System.out.println(new String(bys, 0, len));
// 釋放資源
is.close();
s.close();
}
}
這樣服務端的内容我們也寫完了。測試時需要注意一點,我們要先啟動服務端的程式之後,再啟動用戶端,否則服務端不會收到資料。這就好比是谷歌伺服器沒開,但你去使用google搜東西,這當然是搜不到東西的啦。雖說現在開着,但直接搜仍沒反應Σ( ° △ °|||)︴