Java中的UDP认为UDP具有“连接”

时间:2015-10-21 13:21:12

标签: java sockets udp

Java中的UDP认为UDP具有“连接”。这令我感到惊讶,来自C背景,我一直使用UDP作为一种即发即弃的协议。

在Java中测试UDP时,我注意到如果远程UDP端口没有监听,我在 中尝试发送任何内容之前在Java 中收到错误。

为了能够判断远程UDP端口是否正在侦听,Java做了什么(没有我要求)?

(以下代码在套接字的接收线程中运行。发送在不同的线程中完成。)

    try {
        socket = new DatagramSocket(udpPort);
        socket.connect(udpAddr, udpPort);
    } catch (SocketException e) {
        Log.d(TAG, "disconnected", e);
    }
    ...
    while (true) {
        // TODO: don't create a new datagram for each iteration
        DatagramPacket packet = new DatagramPacket(new byte[BUF_SIZE], BUF_SIZE);
        try {
            socket.receive(packet); // line 106
        } catch (IOException e) {
            Log.d(TAG, "couldn't recv", e);
        }
        ...
如果远程套接字没有收听,

会产生以下错误。

java.net.PortUnreachableException:
        at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:556)
        at libcore.io.IoBridge.recvfrom(IoBridge.java:516)
        at java.net.PlainDatagramSocketImpl.doRecv(PlainDatagramSocketImpl.java:161)
        at java.net.PlainDatagramSocketImpl.receive(PlainDatagramSocketImpl.java:169)
        at java.net.DatagramSocket.receive(DatagramSocket.java:253)
        at com.example.mypkg.MyClass.run(MyClass.java:106)
        at java.lang.Thread.run(Thread.java:856)
 Caused by: libcore.io.ErrnoException: recvfrom failed: ECONNREFUSED (Connection refused)
        at libcore.io.Posix.recvfromBytes(Native Method)
        at libcore.io.Posix.recvfrom(Posix.java:131)
        at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
        ...

3 个答案:

答案 0 :(得分:3)

首先,很明显,这不是使用真正的Java实现的。 " libcore.io"包不是Java SE库的一部分。这些是Android堆栈跟踪。 (这不会改变任何事情......但它可以。)

好的,让我们从异常开始吧。 java.net.PortUnreachableException的javadoc说:

  

"表示已在连接的数据报上收到ICMP Port Unreachable消息。"

对于DatagramSocket.connect(...)

  

"如果套接字所连接的远程目标不存在,或者无法访问,并且如果已收到该地址的ICMP目的地不可达数据包,则后续的发送或接收调用可能会抛出一个PortUnreachableException。注意,不能保证会抛出异常。"

所以,我认为发生了什么。在创建incoming套接字之前,客户端系统上的某些内容已将UDP数据包发送到该端口上的服务器,并且服务器已响应ICMP端口无法访问。然后创建并连接套接字,然后调用receive。这会进行recvfrom系统调用,并且网络堆栈以ECONREFUSED错误代码响应...... Java变为PortUnreachableException

这是否意味着UDP是面向连接的?

不是,IMO。它只是报告它收到了ICMP消息以响应之前发生的事情

connect方法和"连接套接字" /"连接数据报"措辞?

IMO,这只是一些笨拙的措辞。 &#34;连接&#34;实际上只是指数据报套接字绑定到特定的远程地址和端口......这样你就可以发送和接收数据报而无需指定IP和端口 1 < / SUP>。

这些&#34;连接&#34;是非常脆弱的,当然不等于制作UDP&#34;面向连接&#34;。

  

为了能够判断远程UDP端口是否正在侦听,Java做了什么(没有我要求)?

它没有做任何事情。 Java只是报告先前ICMP消息中的信息。

1 - 实际上,还有更多的东西。例如,绑定告诉客户端操作系统缓冲来自该主机/端口的UDP数据包路由UDP数据包(和ICMP通知)到应用程序。它还告诉它不要响应ICMP Port Unreachable。

答案 1 :(得分:3)

  

Java中的UDP认为UDP具有“连接”。

不,它不是,但UDP(不管Java) 是否已连接套接字。不一样。

  

这令我感到惊讶,来自C背景,我一直使用UDP作为一种即发即弃的协议类型。

您也可以在{C}中使用connect() UDP套接字。仔细看看。你所描述的内容与Java没有任何关系。

  

在Java中测试UDP时,我注意到如果远程UDP端口没有监听,我在尝试发送任何内容之前就会收到Java错误。

那是因为你连接了套接字。其中一个副作用是传入的ICMP消息可以以错误的形式路由回发送套接字。

  

为了能够判断远程UDP端口是否正在侦听,Java做了什么(没有我要求)?

它调用BSD套接字connect()方法。

答案 2 :(得分:0)

UDP服务器需要侦听本地端口。

这是服务器的代码存根。

int portNumber = 59123;
DatagramSocket server = new DatagramSocket(portNumber);

// read incoming packets
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while(true)
{
   server.receive(packet);
   byte[] data = packet.getData();
   String text = new String(data, 0, packet.getLength());

   echo(packet.getAddress().getHostAddress() + ":" + packet.getPort() + " received: '" + text + "'");
}