我扼杀了程序并编写了示例,以便它可以通过javac *.java && java Main
注意:这主要是关于TheClient.java
<CommentOutToMakeWork>
和</CommentOutToMakeWork>
之间的行被注释掉,则SocketChannel将被阻止,传输将完成 Main.java
:
import java.io.IOException;
import java.lang.InterruptedException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
public static void main(String[] args) throws ExecutionException, IOException, InterruptedException {
final SocketAddress address = new InetSocketAddress("127.0.0.1", 12345);
final int size = 30 * 1000 * 1000;
ExecutorService executor = Executors.newFixedThreadPool(2);
TheServer theServer = new TheServer(address, size);
TheClient theClient = new TheClient(address, size);
Future<String> serverFuture = executor.submit(theServer);
Thread.sleep(2000);
Future<String> clientFuture = executor.submit(theClient);
System.out.println("MAIN: Received from client: " + clientFuture.get());
System.out.println("MAIN: Received from server: " + serverFuture.get());
executor.shutdown();
}
}
TheClient.java
:
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Random;
import java.util.concurrent.Callable;
class TheClient implements Callable<String> {
private TheClient() {}
public TheClient(SocketAddress address, int size) {
this.size = size;
this.from = new byte[size];
this.serverAddress = address;
new Random().nextBytes(from);
}
private int size;
private byte[] from;
private SocketAddress serverAddress;
public String call() throws IOException {
SocketChannel socketChannel = SocketChannel.open();
System.out.println("CLIENT: Attempting to connect to server...");
socketChannel.connect(serverAddress);
// <CommentOutToMakeWork>
socketChannel.configureBlocking(false);
// </CommentOutToMakeWork>
System.out.println("CLIENT: Connection established. Sending " + size + " bytes.");
// For this example, this is one large write, but even my actual
// program, which uses a loop and puts smaller chunks onto the channel,
// is too fast for the SocketChannel.
socketChannel.write(ByteBuffer.wrap(from));
System.out.println("CLIENT: Write completed.");
return "CLIENT: Success!";
}
}
TheServer.java
:
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.util.Random;
import java.util.concurrent.Callable;
class TheServer implements Callable<String> {
private TheServer() {}
public TheServer(SocketAddress address, int size) {
this.size = size;
this.to = new byte[size];
this.serverAddress = address;
}
private int size;
private byte[] to;
private SocketAddress serverAddress;
public String call() throws IOException {
ServerSocketChannel serverChannel = ServerSocketChannel.open().bind(serverAddress);
System.out.println("SERVER: Awaiting connection...");
InputStream clientSocketInputStream = serverChannel.accept().socket().getInputStream();
System.out.println("SERVER: Connection established. Attempting to read " + size + " bytes.");
for (int i = 0; i < size; ++i) {
to[i] = (byte) clientSocketInputStream.read();
}
System.out.println("SERVER: Read completed.");
return "SERVER: Success!";
}
}
答案 0 :(得分:5)
我认为答案在于WritableByteChannel.write
文档:
除非另有说明,否则只有在写入所有r请求的字节后才会返回写操作。某些类型的通道(取决于它们的状态)可能只写入一些字节或者根本不写。 例如,非阻塞模式下的套接字通道不能再写入套接字输出缓冲区中可用的字节数。
所以看起来你需要使用write
的返回值来找出已经写了多少,并且在没有写完所有内容的情况下处理。从描述中可以清楚地看出如何处理这种情况 - 例如,您可能会发现需要进行一些调度以在套接字输出缓冲区耗尽时继续写入。