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)
...
答案 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
方法和"连接套接字" /"连接数据报"措辞?
这些"连接"是非常脆弱的,当然不等于制作UDP"面向连接"。
为了能够判断远程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 + "'");
}