Using the Sun Java VM 1.5 or 1.6 on Windows, I connect a non-blocking socket. I then fill a ByteBuffer
with a message to output, and attempt to write()
to the SocketChannel.
在Windows上使用Sun Java VM 1.5或1.6,我连接一个非阻塞套接字。然后我用一个消息填充ByteBuffer输出,并尝试write()到SocketChannel。
I expect the write to complete only partially if the amount to be written is greater than the amount of space in the socket's TCP output buffer (this is what I expect intuitively, it's also pretty much my understanding of the docs), but that's not what happens. The write()
always seems to return reporting the full amount written, even if it's several megabytes (the socket's SO_SNDBUF is 8KB, much, much less than my multi-megabyte output message).
如果要写入的数量大于套接字TCP输出缓冲区中的空间量,我希望写入只能部分完成(这是我所期望的直观,这也是我对文档的理解),但那不是什么发生。 write()似乎总是返回报告写入的全部数量,即使它是几兆字节(套接字的SO_SNDBUF是8KB,远远小于我的多兆字节输出消息)。
A problem here is that I can't test the code that handles the case where the output is partially written (registering an interest set of WRITE
to a selector and doing a select()
to wait until the remainder can be written), as that case never seems to happen. What am I not understanding?
这里的一个问题是我无法测试处理部分写入输出的情况的代码(将WRITE的兴趣集注册到选择器并执行select()以等待直到写入其余部分),因为案件似乎永远不会发生。我不明白的是什么?
6 个解决方案
#1
7
I managed to reproduce a situation that might be similar to yours. I think, ironically enough, your recipient is consuming the data faster than you're writing it.
我设法重现了一个可能类似于你的情况。我认为,具有讽刺意味的是,您的收件人比您编写数据的速度更快。
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
public static void main(String[] args) throws Exception {
final ServerSocket ss = new ServerSocket(12345);
final Socket cs = ss.accept();
System.out.println("Accepted connection");
final InputStream in = cs.getInputStream();
final byte[] tmp = new byte[64 * 1024];
while (in.read(tmp) != -1);
Thread.sleep(100000);
}
}
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class MyNioClient {
public static void main(String[] args) throws Exception {
final SocketChannel s = SocketChannel.open();
s.configureBlocking(false);
s.connect(new InetSocketAddress("localhost", 12345));
s.finishConnect();
final ByteBuffer buf = ByteBuffer.allocate(128 * 1024);
for (int i = 0; i < 10; i++) {
System.out.println("to write: " + buf.remaining() + ", written: " + s.write(buf));
buf.position(0);
}
Thread.sleep(100000);
}
}
If you run the above server and then make the above client attempt to write 10 chunks of 128 kB of data, you'll see that every write operation writes the whole buffer without blocking. However, if you modify the above server not to read anything from the connection, you'll see that only the first write operation on the client will write 128 kB, whereas all subsequent writes will return 0
.
如果您运行上述服务器,然后让上面的客户端尝试写入10个128 kB的数据块,您将看到每个写操作都会写入整个缓冲区而不会阻塞。但是,如果您修改上述服务器而不是从连接中读取任何内容,您将看到只有客户端上的第一个写操作将写入128 kB,而所有后续写入将返回0。
Output when the server is reading from the connection:
服务器从连接读取时的输出:
to write: 131072, written: 131072
to write: 131072, written: 131072
to write: 131072, written: 131072
...
Output when the server is not reading from the connection:
服务器未从连接读取时的输出:
to write: 131072, written: 131072
to write: 131072, written: 0
to write: 131072, written: 0
...
#2
2
I've been working with UDP in Java and have seen some really "interesting" and completely undocumented behavior in the Java NIO stuff in general. The best way to determine what is happening is to look at the source which comes with Java.
我一直在使用Java中的UDP,并且在Java NIO中总体上看到了一些非常“有趣”且完全没有文档记录的行为。确定发生了什么的最好方法是查看Java附带的源代码。
I also would wager rather highly that you might find a better implementation of what you're looking for in any other JVM implementation, such as IBM's, but I can't guarantee that without look at them myself.
我也非常高兴你可能会在任何其他JVM实现中找到更好的实现,例如IBM,但我不能保证不自己看它们。
#3
1
I can't find it documented anywhere, but IIRC[1], send() is guaranteed to either a) send the supplied buffer completely, or b) fail. It will never complete the send partially.
我无法在任何地方找到它,但是IIRC [1],send()保证要么a)完全发送提供的缓冲区,要么b)失败。它永远不会完成部分发送。
[1] I've written multiple Winsock implementations (for Win 3.0, Win 95, Win NT, etc), so this may be Winsock-specific (rather than generic sockets) behavior.
[1]我已经编写了多个Winsock实现(用于Win 3.0,Win 95,Win NT等),因此这可能是Winsock特定的(而不是通用套接字)行为。
#4
0
I'll make a big leap of faith and assume that the underlying network provider for Java is the same as for C...the O/S allocates more than just SO_SNDBUF
for every socket. I bet if you put your send code in a for(1,100000) loop, you would eventually get a write that succeeds with a value smaller than requested.
我将实现信念的*,并假设Java的底层网络提供程序与C相同...... O / S为每个套接字分配的不仅仅是SO_SNDBUF。我敢打赌,如果你把你的发送代码放在for(1,100000)循环中,你最终会得到一个成功的写入值小于请求的值。
#5
0
You really should look at an NIO framework like MINA or Grizzly. I've used MINA with great success in an enterprise chat server. It is also used in the Openfire chat server. Grizzly is used in Sun's JavaEE implementation.
你真的应该看看像MINA或Grizzly这样的NIO框架。我在企业聊天服务器上使用MINA取得了巨大成功。它也用于Openfire聊天服务器。 Grizzly用于Sun的JavaEE实现。
#6
0
Where are you sending the data? Keep in mind that the network acts as a buffer that is at least equal in size to your SO_SNDBUF plus the receiver's SO_RCVBUF. Add this to the reading activity by the receiver as mentioned by Alexander and you can get a lot of data soaked up.
你在哪里发送数据?请记住,网络充当缓冲区,其大小至少与SO_SNDBUF和接收器的SO_RCVBUF相等。如Alexander所述,接收器将其添加到阅读活动中,您可以获得大量数据。
#1
7
I managed to reproduce a situation that might be similar to yours. I think, ironically enough, your recipient is consuming the data faster than you're writing it.
我设法重现了一个可能类似于你的情况。我认为,具有讽刺意味的是,您的收件人比您编写数据的速度更快。
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
public static void main(String[] args) throws Exception {
final ServerSocket ss = new ServerSocket(12345);
final Socket cs = ss.accept();
System.out.println("Accepted connection");
final InputStream in = cs.getInputStream();
final byte[] tmp = new byte[64 * 1024];
while (in.read(tmp) != -1);
Thread.sleep(100000);
}
}
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class MyNioClient {
public static void main(String[] args) throws Exception {
final SocketChannel s = SocketChannel.open();
s.configureBlocking(false);
s.connect(new InetSocketAddress("localhost", 12345));
s.finishConnect();
final ByteBuffer buf = ByteBuffer.allocate(128 * 1024);
for (int i = 0; i < 10; i++) {
System.out.println("to write: " + buf.remaining() + ", written: " + s.write(buf));
buf.position(0);
}
Thread.sleep(100000);
}
}
If you run the above server and then make the above client attempt to write 10 chunks of 128 kB of data, you'll see that every write operation writes the whole buffer without blocking. However, if you modify the above server not to read anything from the connection, you'll see that only the first write operation on the client will write 128 kB, whereas all subsequent writes will return 0
.
如果您运行上述服务器,然后让上面的客户端尝试写入10个128 kB的数据块,您将看到每个写操作都会写入整个缓冲区而不会阻塞。但是,如果您修改上述服务器而不是从连接中读取任何内容,您将看到只有客户端上的第一个写操作将写入128 kB,而所有后续写入将返回0。
Output when the server is reading from the connection:
服务器从连接读取时的输出:
to write: 131072, written: 131072
to write: 131072, written: 131072
to write: 131072, written: 131072
...
Output when the server is not reading from the connection:
服务器未从连接读取时的输出:
to write: 131072, written: 131072
to write: 131072, written: 0
to write: 131072, written: 0
...
#2
2
I've been working with UDP in Java and have seen some really "interesting" and completely undocumented behavior in the Java NIO stuff in general. The best way to determine what is happening is to look at the source which comes with Java.
我一直在使用Java中的UDP,并且在Java NIO中总体上看到了一些非常“有趣”且完全没有文档记录的行为。确定发生了什么的最好方法是查看Java附带的源代码。
I also would wager rather highly that you might find a better implementation of what you're looking for in any other JVM implementation, such as IBM's, but I can't guarantee that without look at them myself.
我也非常高兴你可能会在任何其他JVM实现中找到更好的实现,例如IBM,但我不能保证不自己看它们。
#3
1
I can't find it documented anywhere, but IIRC[1], send() is guaranteed to either a) send the supplied buffer completely, or b) fail. It will never complete the send partially.
我无法在任何地方找到它,但是IIRC [1],send()保证要么a)完全发送提供的缓冲区,要么b)失败。它永远不会完成部分发送。
[1] I've written multiple Winsock implementations (for Win 3.0, Win 95, Win NT, etc), so this may be Winsock-specific (rather than generic sockets) behavior.
[1]我已经编写了多个Winsock实现(用于Win 3.0,Win 95,Win NT等),因此这可能是Winsock特定的(而不是通用套接字)行为。
#4
0
I'll make a big leap of faith and assume that the underlying network provider for Java is the same as for C...the O/S allocates more than just SO_SNDBUF
for every socket. I bet if you put your send code in a for(1,100000) loop, you would eventually get a write that succeeds with a value smaller than requested.
我将实现信念的*,并假设Java的底层网络提供程序与C相同...... O / S为每个套接字分配的不仅仅是SO_SNDBUF。我敢打赌,如果你把你的发送代码放在for(1,100000)循环中,你最终会得到一个成功的写入值小于请求的值。
#5
0
You really should look at an NIO framework like MINA or Grizzly. I've used MINA with great success in an enterprise chat server. It is also used in the Openfire chat server. Grizzly is used in Sun's JavaEE implementation.
你真的应该看看像MINA或Grizzly这样的NIO框架。我在企业聊天服务器上使用MINA取得了巨大成功。它也用于Openfire聊天服务器。 Grizzly用于Sun的JavaEE实现。
#6
0
Where are you sending the data? Keep in mind that the network acts as a buffer that is at least equal in size to your SO_SNDBUF plus the receiver's SO_RCVBUF. Add this to the reading activity by the receiver as mentioned by Alexander and you can get a lot of data soaked up.
你在哪里发送数据?请记住,网络充当缓冲区,其大小至少与SO_SNDBUF和接收器的SO_RCVBUF相等。如Alexander所述,接收器将其添加到阅读活动中,您可以获得大量数据。