上一篇文章中,我發現了UDP也是有這connect方法的,這使我非常不理解,下面爲大家講解一下這個connect方法。
我們知道UDP是無連接的,它可以給多個IP發送數據包,包括廣播地址或者多播通信的實現,而這些是TCP/IP無法實現的。
但是UDP提供了這樣的一個connect()方法,它有兩種使用方式,當使用了這個方法之後,那麼就限定了這個socket的使用範圍: 只允許從這個指定的SocketAddress 上獲得數據包和向這個指定的SocketAddress 發送數據包, 當你一旦通過這個socket向別的地址發送了數據包,或者接收到了不是這個地址發送來的數據包,那麼程序就會拋出IllegalArgumentException 異常, 特殊的是如果指定的這個SocketAddress 是個多播地址或者廣播地址,那麼只允許向這個地址發送數據包,不允許從這個地址接收數據包。
// SocketAddress 其實就是IP地址+端口號 , 而InetAddress 只有IP地址
connect(InetAddress address, int port)
connect(SocketAddress addr)
UDP通過這樣的方式,限定了單向的通信,但是注意的是,這裏的限定只是僅限於一方,而並沒有限制另外一方,另外一方依舊是可以向多個IP地址發送數據包的,因此這和TCP/IP 是極大的不同。TCP/IP的connect()是要有一個三次握手的過程的,而UDP的connect顯然沒有,它只是將IP地址和端口號進行了存儲,對要進行通信的對象做了一個限制。 而且 TCP/IP的connect()只可以進行一次,但是UDP的connect()可以調用多次, 每次重新調用connect(SocketAddress ),就是將原來限制通信的對象修改爲新的這個地址的對象, 或者調用disConnect() 方法,就會解除對通信對象的限制,這樣這個socket就又可以多向的通信了。
當我們進行UDP通信的對象只有一個時,建議使用connect()方法,使用了這個方法之後有一個極大的好處:
當我們使用了connect(SocketAddress addr) 方法時,那麼在socket對象裏面就會將發送方的地址設置爲此地址,那麼發送的數據包對象就不用顯式的標明 IP地址和 Port ,這樣在調用send(packet)方法時,就不會對數據包再進行 IP地址和Port的安全檢查,要發送的數據包少時優勢體現不出來,但是當數據包多時,可以節省大量的時間。
send方法的源碼:
public void send(DatagramPacket p) throws IOException {
InetAddress packetAddress = null;
synchronized (p) {
if (isClosed())
throw new SocketException("Socket is closed");
checkAddress (p.getAddress(), "send");
// ST_NOT_CONNECTED 表示着當前沒有要限制通信的對象
if (connectState == ST_NOT_CONNECTED) {
// check the address is ok wiht the security manager on every send.
SecurityManager security = System.getSecurityManager();
// The reason you want to synchronize on datagram packet
// is because you dont want an applet to change the address
// while you are trying to send the packet for example
// after the security check but before the send.
// 進行IP 和 port 的安全檢查
if (security != null) {
if (p.getAddress().isMulticastAddress()) {
security.checkMulticast(p.getAddress());
} else {
security.checkConnect(p.getAddress().getHostAddress(),
p.getPort());
}
}
} else {
// we're connected
packetAddress = p.getAddress();
if (packetAddress == null) {
p.setAddress(connectedAddress);
p.setPort(connectedPort);
} else if ((!packetAddress.equals(connectedAddress)) ||
p.getPort() != connectedPort) {
throw new IllegalArgumentException("connected address " +
"and packet address" +
" differ");
}
}
// Check whether the socket is bound
if (!isBound())
bind(new InetSocketAddress(0));
// call the method to send
getImpl().send(p);
}
}
期間還看到了一個:
bind(SocketAddress addr) 方法,是用來爲創建的socket對象綁定到一個指定的 IP 地址和 Port號的,這個指定的是自身的IP和Port ,和上面的指定的要進行通信的對象的 IP 和 Port 不是一回事。