Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么即使在非阻塞套接字上,SocketChannel写入也总是完整的?_Java_Sockets_Network Programming_Nio - Fatal编程技术网

Java 为什么即使在非阻塞套接字上,SocketChannel写入也总是完整的?

Java 为什么即使在非阻塞套接字上,SocketChannel写入也总是完整的?,java,sockets,network-programming,nio,Java,Sockets,Network Programming,Nio,在Windows上使用Sun Java VM 1.5或1.6,我连接了一个非阻塞套接字。然后,我用一条要输出的消息填充一个ByteBuffer,并尝试write()到SocketChannel 如果要写入的量大于套接字的TCP输出缓冲区中的空间量(这是我直觉上所期望的,这也是我对的理解),我希望写入只完成一部分,但事实并非如此。write()似乎总是返回报告全部写入量,即使是数兆字节(套接字的sou SNDBUF是8KB,比我的数兆字节输出消息少得多) 这里的一个问题是,我无法测试处理部分写入输

在Windows上使用Sun Java VM 1.5或1.6,我连接了一个非阻塞套接字。然后,我用一条要输出的消息填充一个
ByteBuffer
,并尝试
write()
到SocketChannel

如果要写入的量大于套接字的TCP输出缓冲区中的空间量(这是我直觉上所期望的,这也是我对的理解),我希望写入只完成一部分,但事实并非如此。
write()
似乎总是返回报告全部写入量,即使是数兆字节(套接字的sou SNDBUF是8KB,比我的数兆字节输出消息少得多)


这里的一个问题是,我无法测试处理部分写入输出的情况的代码(将
WRITE
的兴趣集注册到选择器并执行
select()
以等待剩余部分可以写入),因为这种情况似乎从未发生过。我还不明白什么?

我会大踏步地相信,Java的底层网络提供商与C的底层网络提供商是一样的。O/S不仅仅为每个套接字分配
,所以_SNDBUF
。我敢打赌,如果您将发送代码放入for(1100000)循环,您最终会得到一个成功的写入,其值小于请求的值。

我一直在Java中使用UDP,并且在Java NIO中看到了一些非常“有趣”且完全没有文档记录的行为。确定发生了什么的最好方法是查看Java附带的源代码


我还敢打赌,您可能会在任何其他JVM实现(如IBM)中找到更好的实现,但如果不亲自查看它们,我无法保证这一点。

我成功地重现了一种可能与您类似的情况。我认为,具有讽刺意味的是,您的收件人使用数据的速度比您编写数据的速度快

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);
  }
}
服务器未读取连接时的输出:

to write: 131072, written:  131072
to write: 131072, written:  131072
to write: 131072, written:  131072
...
to write: 131072, written:  131072
to write: 131072, written:  0
to write: 131072, written:  0
...  

您真的应该看看像or这样的NIO框架。我已经在企业聊天服务器中成功地使用了MINA。它也用于聊天服务器。Grizzly用于Sun的JavaEE实现。

您将数据发送到哪里?请记住,网络充当的缓冲区大小至少等于您的SO_SNDBUF加上接收方的SO_RCVBUF。如Alexander所述,将此添加到接收器的读取活动中,您可以吸收大量数据。

我在任何地方都找不到记录,但IIRC[1],send()保证a)完全发送提供的缓冲区,或b)失败。它永远不会部分完成发送


[1] 我已经编写了多个Winsock实现(针对Win 3.0、Win 95、Win NT等),因此这可能是Winsock特有的(而不是通用套接字)行为。

感谢您的想法。我只写了几百个数兆字节的数据,但没有一个返回的值小于全部数据量。你有没有可能用嗅探器观察流量,看看数据包是如何发送的?如果发送库甚至试图将数据包分解为比MTU块更小的数据包,则可能会给您一个线索。更新:我尝试了Sun VM 1.5、1.6和JRockit VM 1.5,以确保此网络行为不是特定于VM的。是的,但在TCP中,不会有任何传输中的数据不在发送缓冲区中。这是不正确的。在非阻塞模式下,它可以返回
0