Java网络编程从入门到精通(14):多种多样的建立网络连接的方式
生活随笔
收集整理的這篇文章主要介紹了
Java网络编程从入门到精通(14):多种多样的建立网络连接的方式
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在上一篇文章中我們討論了Socket類的基本用法,并給出的例子中使用Socket類連接服務器時使用了一種最簡單的連接方式,也就是通過IP和端口號來連接服務器。而為了使連接服務器的方式更靈活,Socket類不僅可以通過自身的構造方法連接服務器,而且也可以通過connect方法來連接數據庫。 一、通過構造方法連接服務器 ??? 我們可以通過6個重載構造函數以不同的方式來連接服務器。這6個重載的構造函數可以分為兩類:
1. 自動選擇IP
??? 這種方式是最常用的。所謂自動選擇IP,是指當本機有多塊網卡或者在一個網卡上綁定了多個IP時,Socket類會自動為我們選擇一個可用的IP。在上述6個構造方法中有4個是使用這種方法來連接服務器的。
<!--[if !supportLists]-->(1)??? <!--[endif]-->public Socket(String host, int port) <?XML:NAMESPACE PREFIX = O /> 這是最常用的構造方法,在前面的例子中就是使用的這個構造方法。在使用時只需要提供一個字符串類型的IP或域名以及一個整型的端口號即可。在這個構造方法中可能會拋出兩個錯誤:UnknownHostException和IOException。發生第一個錯誤的原因是我們提供的host并不存在或不合法,而其它的錯誤被歸為IO錯誤。因此,這個構造方法的完整定義是: public?Socket(String?host,?int?port)?throws?UnknownHostException,?IOException (2) public Socket(InetAddress inetaddress, int port) 這個構造方法和第一種構造方法類似,只是將字符串形式的host改為InetAddress對象類型了。在這個構造方法中之所以要使用InetAddress類主要是因為考慮到在程序中可能需要使用Socket類多次連接同一個IP或域名,這樣使用InetAddress類的效率比較高。另外,在使用字符串類型的host連接服務器時,可能會發生兩個錯誤,但使用InetAddress對象來描述host,只會發生IOException錯誤,這是因為當你將IP或域名傳給InetAddress時,InetAddress會自動檢查這個IP或域名,如果這個IP或域名無效,那么InetAddress就會拋出UnknownHostException錯誤,而不會由Socket類的構造方法拋出。因此,這個構造方法的完整定義是:
public?Socket(InetAddress?inetaddress,?int?port)?throws?IOException (3) public Socket(String host, int port, boolean stream) 這個構造方法和第一種構造方法差不多,只是多了一個boolean類型的stream參數。如果這個stream為true,那么這個構造方法和第一種構造方法完全一樣。如果stream為false,則使用UDP協議建立一個UDP連接(UDP將在下面的章節詳細討論,在這里只要知道它和TCP最大的區別是UDP是面向無連接的,而TCP是面向有連接的),也許是當初Sun的開發人員在編寫Socket類時還未考慮編寫處理UDP連接的DatagramSocket類,所以才將建立UDP連接的功能加入到Socket類中,不過Sun在后來的JDK中加入了DatagramSocket類,所以,這個構造方法就沒什么用了,因此,Sun將其設為了Deprecated標記,也就是說,這個構造方法在以后的JDK版本中可以會被刪除。其于以上原因,在使用Java編寫網絡程序時,盡量不要使用這個構造方法來建立UDP連接。
(4) public Socket(InetAddress inetaddress, int port, boolean flag) 這個構造方法和第三種構造方法的flag標記的含義一樣,也是不建議使用的。
??? 下面的代碼演示上述4種構造方法的使用:
package mysocket;
import?java.net.*;
import?java.io.*;
public?class MoreConnection
{
????private?static?void?closeSocket(Socket?socket)
????{
????????if?(socket?!=?null)
????????????try
????????????{
????????????????socket.close();
????????????}
????????????catch?(Exception?e)?{?}
????}
????public?static?void?main(String[]?args)
????{
????????Socket?socket1?=?null,?socket2?=?null,?socket3?=?null,?socket4?=?null;
????????try
????????{
????????????//?如果將www.ptpress.com.cn改成其它不存在的域名,將拋出UnknownHostException錯誤
????????????//?測試public?Socket(String?host,?int?port)
????????????socket1?=?new?Socket("www.ptpress.com.cn",?80);
????????????System.out.println("socket1連接成功!");
????????????//?測試public?Socket(InetAddress?inetaddress,?int?port)
????????????socket2?=?new?Socket(InetAddress.getByName("www.ptpress.com.cn"), 80);
????????????System.out.println("socket2連接成功!");
????????????//?下面的兩種建立連接的方式并不建議使用
????????????//?測試public?Socket(String?host,?int?port,?boolean?stream)
????????????socket3?=?new?Socket("www.ptpress.com.cn",?80,?false);
????????????System.out.println("socket3連接成功!");
????????????//?測試public?Socket(InetAddress?inetaddress,?int?i,?boolean?flag)
????????????socket4?=?new?Socket(InetAddress.getByName("www.ptpress.com.cn"), 80,?false);
????????????System.out.println("socket4連接成功!");
????????}
????????catch?(UnknownHostException?e)
????????{
????????????System.out.println("UnknownHostException?被拋出!");
????????}
????????catch?(IOException?e)
????????{
????????????System.out.println("IOException?被拋出!");
????????}
????????finally
????????{
????????????closeSocket(socket1);
????????????closeSocket(socket2);
????????????closeSocket(socket3);
????????????closeSocket(socket4);
????????}
????}
}
在上面代碼中的最后通過finally關閉了被打開的Socket連接,這是一個好習慣。因為只有在將關閉Socket連接的代碼寫在finally里,無論是否出錯,都會執行這些代碼。但要注意,在關閉Socket連接之前,必須檢查Socket對象是否為null,這是因為錯誤很可能在建立連接時發生,這樣Socket對象就沒有建立成功,也就用不著關閉了。
1.?????? 手動綁定IP 當本機有多個IP時(這些IP可能是多塊網卡上的,也可能是一塊網卡上綁定的多個IP),在連接服務器時需要由客戶端確定需要使用哪個IP。這樣就必須使用Socket類的另外兩個構方法來處理。下面讓我們來看看這兩個構造方法是如何來使用特定的IP來連接服務器的。 public Socket(String host, int port, InetAddress inetaddress, int localPort) 這個構造方法的參數分為兩部分,第一部分為前兩個參數:host和port,它們分別表示要連接的服務器的IP和端口號。第二部分為后兩個參數:inetaddress和localPort。其中inetaddress則表示要使用的本地的IP,而localPort則表示要綁定的本地端口號。這個localPort這以設置為本機的任何未被綁定的端口號。如果將localPort的值設為0,java將在1024到65,535之間隨即選擇一個未綁定的端口號。因此,在一般情況下將localPort設為0。 public Socket(InetAddress inetaddress, int port, InetAddress inetaddress1, int localPort) 這個構造方法和第一個構造方法基本相同,只是將第一個參數host換成了inetaddress。其它的使用方法和第一個構造方法類似。 在下面的代碼中將使用這兩個構造方法來做一個實驗。我們假設有兩臺計算機:PC1和PC2。PC1和PC2各有一塊網卡。PC1綁定有兩個IP:192.168.18.252和200.200.200.200。PC2綁定有一個IP:200.200.200.4。PC1和PC2的子網掩碼都是255.255.255.0。而PC1的默認網關為:192.168.28.254。下面的代碼需要在PC1上運行。
package mysocket;
import?java.net.*;
public?class MoreConnection1
{
????public?static?void?main(String[]?args)
????{
????????try
????????{
????????????InetAddress?localAddress1?=?InetAddress.getByName("200.200.200.200");
????????????InetAddress?localAddress2?=?InetAddress.getByName("192.168.18.252");
??????????? // 如果將localAddress1改成localAddress2,socket1無法連接成功
????????????Socket?socket1?=?new?Socket("200.200.200.4",?80,?localAddress1,?0);
????????????System.out.println("socket1連接成功!");
????????????Socket?socket2?=?new?Socket("www.ptpress.com.cn",?80, localAddress2,?0);
????????????System.out.println("socket2連接成功!");
????????????//?下面的語句將拋出一個IOException錯誤
????????????Socket?socket3?=?new?Socket("www.ptpress.com.cn",?80, localAddress1,?0);
????????????System.out.println("socket3連接成功!");
????????????socket1.close();
????????????socket2.close();
????????????socket3.close();
????????}
????????catch?(Exception?e)
????????{
????????????System.out.println(e.getMessage());
????????}
????}
}
運行上面代碼的輸出結果如下: socket1連接成功!
socket2連接成功!
Connection?timed?out:?connect
從上面的輸出結果可以看出,socket1和socket2已經連接成功,而socket3并未連接成功。從例程4-8可以看出,socket1在連接時使用localAddress1綁定到了200.200.200.200上,而PC2的IP是200.200.200.4,因此,socket1所使用的IP和PC2的IP在同一個網段,所以socket1可以連接成功。如果將localAddress1改成localAddress2后,socket1將無法連接成功。另外兩個Socket連接socket2和socket3是通過Internet連接www.ptpress.com.cn。它們所不同的是socket2綁定的是192.168.18.252,而socket3綁定的是200.200.200.200。它們執行的結果是socket2可以連接成功,而socket3連接失敗。這是因為socket2所綁定的IP和PC1的默認網關192.168.18.254在同一個網段,因此,socket2可以連接到Internet。而socket3所綁定的IP和PC1的IP不在同一個網段,因此,socket3將無法連接到Internet。
二、通過connect方法連接服務器 Socket類不僅可以通過構造方法直接連接服務器,而且還可以建立未連接的Socket對象,并通過connect方法來連接服務器。Socket類的connect方法有兩個重載形式: 1. public void connect(SocketAddress endpoint) throws IOException Socket類的connect方法和它的構造方法在描述服務器信息(IP和端口)上有一些差異。在connect方法中并未象構造方法中以字符串形式的host和整數形式的port作為參數,而是直接將IP和端口封裝在了SocketAddress類的子類InetSocketAddress中。可按如下形式使用這個connect方法: Socket?socket?=?new?Socket();
socket.connect(new?InetSocketAddress(host,?port));
2.? public void connect(SocketAddress endpoint, int timeout) throws IOException ??? 這個connect方法和第一個connect類似,只是多了一個timeout參數。這個參數表示連接的超時時間,單位是毫秒。使用timeout設為0,則使用默認的超時時間。 在使用Socket類的構造方法連接服務器時可以直接通過構造方法綁定本地IP,而connect方法可以通過Socket類的bind方法來綁定本地IP。例程4-9演示如何使用connect方法和bind方法。
package mysocket;
import?java.net.*;
public?class MoreConnection2
{
????public?static?void?main(String[]?args)
????{
????????try
????????{
????????????Socket?socket1?=?new?Socket();
????????????Socket?socket2?=?new?Socket();
????????????Socket?socket3?=?new?Socket();
????????????socket1.connect(new?InetSocketAddress("200.200.200.4",?80));
????????????socket1.close();
????????????System.out.println("socket1連接成功!");?????????????
????????????/*
???????????????將socket2綁定到192.168.18.252將產生一個IOException錯誤??
????????????socket2.bind(new?InetSocketAddress("192.168.18.252",?0));
????????????*/
????????????socket2.bind(new?InetSocketAddress("200.200.200.200",?0));
????????????socket2.connect(new?InetSocketAddress("200.200.200.4",?80));
?????????????
????????????socket2.close();
????????????System.out.println("socket2連接成功!");
????????????socket3.bind(new?InetSocketAddress("192.168.18.252",?0));
????????????socket3.connect(new?InetSocketAddress("200.200.200.4",?80),?2000);????????????
????????????socket3.close();
????????????System.out.println("socket3連接成功!");
????????}
????????catch?(Exception?e)
????????{
????????????System.out.println(e.getMessage());
????????}
????}
}
上面的代碼的輸出結果為:
socket1連接成功!
socket2連接成功!
Connection?timed?out:?connect
在上面代碼中的socket3連接服務器時為其設置了超時時間(2000毫秒),因此,socket3在非常短的時間就拋出了IOException錯誤。 ? ? ? 國內最棒的Google Android技術社區(eoeandroid),歡迎訪問!
《銀河系列原創教程》發布
《Java Web開發速學寶典》出版,歡迎定購
1. 自動選擇IP
??? 這種方式是最常用的。所謂自動選擇IP,是指當本機有多塊網卡或者在一個網卡上綁定了多個IP時,Socket類會自動為我們選擇一個可用的IP。在上述6個構造方法中有4個是使用這種方法來連接服務器的。
<!--[if !supportLists]-->(1)??? <!--[endif]-->public Socket(String host, int port) <?XML:NAMESPACE PREFIX = O /> 這是最常用的構造方法,在前面的例子中就是使用的這個構造方法。在使用時只需要提供一個字符串類型的IP或域名以及一個整型的端口號即可。在這個構造方法中可能會拋出兩個錯誤:UnknownHostException和IOException。發生第一個錯誤的原因是我們提供的host并不存在或不合法,而其它的錯誤被歸為IO錯誤。因此,這個構造方法的完整定義是: public?Socket(String?host,?int?port)?throws?UnknownHostException,?IOException (2) public Socket(InetAddress inetaddress, int port) 這個構造方法和第一種構造方法類似,只是將字符串形式的host改為InetAddress對象類型了。在這個構造方法中之所以要使用InetAddress類主要是因為考慮到在程序中可能需要使用Socket類多次連接同一個IP或域名,這樣使用InetAddress類的效率比較高。另外,在使用字符串類型的host連接服務器時,可能會發生兩個錯誤,但使用InetAddress對象來描述host,只會發生IOException錯誤,這是因為當你將IP或域名傳給InetAddress時,InetAddress會自動檢查這個IP或域名,如果這個IP或域名無效,那么InetAddress就會拋出UnknownHostException錯誤,而不會由Socket類的構造方法拋出。因此,這個構造方法的完整定義是:
public?Socket(InetAddress?inetaddress,?int?port)?throws?IOException (3) public Socket(String host, int port, boolean stream) 這個構造方法和第一種構造方法差不多,只是多了一個boolean類型的stream參數。如果這個stream為true,那么這個構造方法和第一種構造方法完全一樣。如果stream為false,則使用UDP協議建立一個UDP連接(UDP將在下面的章節詳細討論,在這里只要知道它和TCP最大的區別是UDP是面向無連接的,而TCP是面向有連接的),也許是當初Sun的開發人員在編寫Socket類時還未考慮編寫處理UDP連接的DatagramSocket類,所以才將建立UDP連接的功能加入到Socket類中,不過Sun在后來的JDK中加入了DatagramSocket類,所以,這個構造方法就沒什么用了,因此,Sun將其設為了Deprecated標記,也就是說,這個構造方法在以后的JDK版本中可以會被刪除。其于以上原因,在使用Java編寫網絡程序時,盡量不要使用這個構造方法來建立UDP連接。
(4) public Socket(InetAddress inetaddress, int port, boolean flag) 這個構造方法和第三種構造方法的flag標記的含義一樣,也是不建議使用的。
??? 下面的代碼演示上述4種構造方法的使用:
package mysocket;
import?java.net.*;
import?java.io.*;
public?class MoreConnection
{
????private?static?void?closeSocket(Socket?socket)
????{
????????if?(socket?!=?null)
????????????try
????????????{
????????????????socket.close();
????????????}
????????????catch?(Exception?e)?{?}
????}
????public?static?void?main(String[]?args)
????{
????????Socket?socket1?=?null,?socket2?=?null,?socket3?=?null,?socket4?=?null;
????????try
????????{
????????????//?如果將www.ptpress.com.cn改成其它不存在的域名,將拋出UnknownHostException錯誤
????????????//?測試public?Socket(String?host,?int?port)
????????????socket1?=?new?Socket("www.ptpress.com.cn",?80);
????????????System.out.println("socket1連接成功!");
????????????//?測試public?Socket(InetAddress?inetaddress,?int?port)
????????????socket2?=?new?Socket(InetAddress.getByName("www.ptpress.com.cn"), 80);
????????????System.out.println("socket2連接成功!");
????????????//?下面的兩種建立連接的方式并不建議使用
????????????//?測試public?Socket(String?host,?int?port,?boolean?stream)
????????????socket3?=?new?Socket("www.ptpress.com.cn",?80,?false);
????????????System.out.println("socket3連接成功!");
????????????//?測試public?Socket(InetAddress?inetaddress,?int?i,?boolean?flag)
????????????socket4?=?new?Socket(InetAddress.getByName("www.ptpress.com.cn"), 80,?false);
????????????System.out.println("socket4連接成功!");
????????}
????????catch?(UnknownHostException?e)
????????{
????????????System.out.println("UnknownHostException?被拋出!");
????????}
????????catch?(IOException?e)
????????{
????????????System.out.println("IOException?被拋出!");
????????}
????????finally
????????{
????????????closeSocket(socket1);
????????????closeSocket(socket2);
????????????closeSocket(socket3);
????????????closeSocket(socket4);
????????}
????}
}
在上面代碼中的最后通過finally關閉了被打開的Socket連接,這是一個好習慣。因為只有在將關閉Socket連接的代碼寫在finally里,無論是否出錯,都會執行這些代碼。但要注意,在關閉Socket連接之前,必須檢查Socket對象是否為null,這是因為錯誤很可能在建立連接時發生,這樣Socket對象就沒有建立成功,也就用不著關閉了。
1.?????? 手動綁定IP 當本機有多個IP時(這些IP可能是多塊網卡上的,也可能是一塊網卡上綁定的多個IP),在連接服務器時需要由客戶端確定需要使用哪個IP。這樣就必須使用Socket類的另外兩個構方法來處理。下面讓我們來看看這兩個構造方法是如何來使用特定的IP來連接服務器的。 public Socket(String host, int port, InetAddress inetaddress, int localPort) 這個構造方法的參數分為兩部分,第一部分為前兩個參數:host和port,它們分別表示要連接的服務器的IP和端口號。第二部分為后兩個參數:inetaddress和localPort。其中inetaddress則表示要使用的本地的IP,而localPort則表示要綁定的本地端口號。這個localPort這以設置為本機的任何未被綁定的端口號。如果將localPort的值設為0,java將在1024到65,535之間隨即選擇一個未綁定的端口號。因此,在一般情況下將localPort設為0。 public Socket(InetAddress inetaddress, int port, InetAddress inetaddress1, int localPort) 這個構造方法和第一個構造方法基本相同,只是將第一個參數host換成了inetaddress。其它的使用方法和第一個構造方法類似。 在下面的代碼中將使用這兩個構造方法來做一個實驗。我們假設有兩臺計算機:PC1和PC2。PC1和PC2各有一塊網卡。PC1綁定有兩個IP:192.168.18.252和200.200.200.200。PC2綁定有一個IP:200.200.200.4。PC1和PC2的子網掩碼都是255.255.255.0。而PC1的默認網關為:192.168.28.254。下面的代碼需要在PC1上運行。
package mysocket;
import?java.net.*;
public?class MoreConnection1
{
????public?static?void?main(String[]?args)
????{
????????try
????????{
????????????InetAddress?localAddress1?=?InetAddress.getByName("200.200.200.200");
????????????InetAddress?localAddress2?=?InetAddress.getByName("192.168.18.252");
??????????? // 如果將localAddress1改成localAddress2,socket1無法連接成功
????????????Socket?socket1?=?new?Socket("200.200.200.4",?80,?localAddress1,?0);
????????????System.out.println("socket1連接成功!");
????????????Socket?socket2?=?new?Socket("www.ptpress.com.cn",?80, localAddress2,?0);
????????????System.out.println("socket2連接成功!");
????????????//?下面的語句將拋出一個IOException錯誤
????????????Socket?socket3?=?new?Socket("www.ptpress.com.cn",?80, localAddress1,?0);
????????????System.out.println("socket3連接成功!");
????????????socket1.close();
????????????socket2.close();
????????????socket3.close();
????????}
????????catch?(Exception?e)
????????{
????????????System.out.println(e.getMessage());
????????}
????}
}
運行上面代碼的輸出結果如下: socket1連接成功!
socket2連接成功!
Connection?timed?out:?connect
從上面的輸出結果可以看出,socket1和socket2已經連接成功,而socket3并未連接成功。從例程4-8可以看出,socket1在連接時使用localAddress1綁定到了200.200.200.200上,而PC2的IP是200.200.200.4,因此,socket1所使用的IP和PC2的IP在同一個網段,所以socket1可以連接成功。如果將localAddress1改成localAddress2后,socket1將無法連接成功。另外兩個Socket連接socket2和socket3是通過Internet連接www.ptpress.com.cn。它們所不同的是socket2綁定的是192.168.18.252,而socket3綁定的是200.200.200.200。它們執行的結果是socket2可以連接成功,而socket3連接失敗。這是因為socket2所綁定的IP和PC1的默認網關192.168.18.254在同一個網段,因此,socket2可以連接到Internet。而socket3所綁定的IP和PC1的IP不在同一個網段,因此,socket3將無法連接到Internet。
二、通過connect方法連接服務器 Socket類不僅可以通過構造方法直接連接服務器,而且還可以建立未連接的Socket對象,并通過connect方法來連接服務器。Socket類的connect方法有兩個重載形式: 1. public void connect(SocketAddress endpoint) throws IOException Socket類的connect方法和它的構造方法在描述服務器信息(IP和端口)上有一些差異。在connect方法中并未象構造方法中以字符串形式的host和整數形式的port作為參數,而是直接將IP和端口封裝在了SocketAddress類的子類InetSocketAddress中。可按如下形式使用這個connect方法: Socket?socket?=?new?Socket();
socket.connect(new?InetSocketAddress(host,?port));
2.? public void connect(SocketAddress endpoint, int timeout) throws IOException ??? 這個connect方法和第一個connect類似,只是多了一個timeout參數。這個參數表示連接的超時時間,單位是毫秒。使用timeout設為0,則使用默認的超時時間。 在使用Socket類的構造方法連接服務器時可以直接通過構造方法綁定本地IP,而connect方法可以通過Socket類的bind方法來綁定本地IP。例程4-9演示如何使用connect方法和bind方法。
package mysocket;
import?java.net.*;
public?class MoreConnection2
{
????public?static?void?main(String[]?args)
????{
????????try
????????{
????????????Socket?socket1?=?new?Socket();
????????????Socket?socket2?=?new?Socket();
????????????Socket?socket3?=?new?Socket();
????????????socket1.connect(new?InetSocketAddress("200.200.200.4",?80));
????????????socket1.close();
????????????System.out.println("socket1連接成功!");?????????????
????????????/*
???????????????將socket2綁定到192.168.18.252將產生一個IOException錯誤??
????????????socket2.bind(new?InetSocketAddress("192.168.18.252",?0));
????????????*/
????????????socket2.bind(new?InetSocketAddress("200.200.200.200",?0));
????????????socket2.connect(new?InetSocketAddress("200.200.200.4",?80));
?????????????
????????????socket2.close();
????????????System.out.println("socket2連接成功!");
????????????socket3.bind(new?InetSocketAddress("192.168.18.252",?0));
????????????socket3.connect(new?InetSocketAddress("200.200.200.4",?80),?2000);????????????
????????????socket3.close();
????????????System.out.println("socket3連接成功!");
????????}
????????catch?(Exception?e)
????????{
????????????System.out.println(e.getMessage());
????????}
????}
}
上面的代碼的輸出結果為:
socket1連接成功!
socket2連接成功!
Connection?timed?out:?connect
在上面代碼中的socket3連接服務器時為其設置了超時時間(2000毫秒),因此,socket3在非常短的時間就拋出了IOException錯誤。 ? ? ? 國內最棒的Google Android技術社區(eoeandroid),歡迎訪問!
《銀河系列原創教程》發布
《Java Web開發速學寶典》出版,歡迎定購
總結
以上是生活随笔為你收集整理的Java网络编程从入门到精通(14):多种多样的建立网络连接的方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (实验学习)MATLAB与C/C++混合
- 下一篇: 在SQL中使用convert函数进行日期