UDP中的connect方法 和TCP的connect方法詳解

上一篇文章中,我發現了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 不是一回事。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章