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 不是一回事。

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