我使用带有reactor模式的NIO将服务器连接到客户端。我的代码如下:
服务器端代码,位于if(selectionKey.isWritable){} :
public void isWritable(SelectionKey selectionKey) throws Exception {
SocketChannel socketChannel =
(SocketChannel) selectionKey.channel();
Integer myInteger = (Integer) selectionKey.attachment();
if (myInteger == null){
int myJob = jobFacade.isAnyJob(socketChannel, 100 /*deadline*/);
if (myJob > 0){
ByteBuffer inputBuffer = ByteBuffer.wrap("available\n".getBytes("UTF-8"));
socketChannel.write(inputBuffer);
myInteger = myJob;
socketChannel.register(
selector, SelectionKey.OP_WRITE, myInteger);
}else if (myJob == -1){
ByteBuffer inputBuffer = ByteBuffer.wrap("unavailable\n".getBytes("UTF-8"));
socketChannel.write(inputBuffer);
socketChannel.close();
UnsupportedOperationException un = new UnsupportedOperationException();
throw un;
}else if (myJob == -2){
ByteBuffer inputBuffer = ByteBuffer.wrap("pending\n".getBytes("UTF-8"));
inputBuffer.flip();
socketChannel.write(inputBuffer);
myInteger = null;
socketChannel.register(
selector, SelectionKey.OP_WRITE, myInteger);
}
// is there any new job to do?
}else{
int myInt = myInteger.intValue();
if ( myInt > 0 ){
long startRange = jobFacade.findByID(myInt);
sendTextFile(startRange, Integer.parseInt(properties.getProperty("workUnit")),
properties.getProperty("textPath"), socketChannel);
myInteger = -3;
socketChannel.register(
selector, SelectionKey.OP_WRITE, myInteger);
}else if (myInt == -3){
sendAlgorithmFile(socketChannel, properties.getProperty("algorithmPath"));
myInteger = -4;
socketChannel.register(
selector, SelectionKey.OP_WRITE, myInteger);
// send algorithm file
}else if (myInt == -4){
int isOK = jobFacade.isAccepted(socketChannel.socket().getInetAddress().toString(),
Long.parseLong(properties.getProperty("deadline")));
if(isOK == -1){
ByteBuffer inputBuffer = ByteBuffer.wrap("notaccepted\n".getBytes("UTF-8"));
socketChannel.write(inputBuffer);
myInteger = null;
socketChannel.register(
selector, SelectionKey.OP_WRITE, myInteger);
}else {
ByteBuffer inputBuffer = ByteBuffer.wrap("accepted\n".getBytes("UTF-8"));
socketChannel.write(inputBuffer);
myInteger = isOK;
socketChannel.register(
selector, SelectionKey.OP_READ, myInteger);
}
// send "accepted" or "not accepted"
}
}
}
除了这些方法首先使用此顺序生成数字之外,无需知道每个块中的方法。 1)myInteger = null,2)myInteger> 0,3)myInteger = -3,4)myInteger = -4 按此顺序,OP-WRITE将连续注册四次。这一部分非常重要。所以让我们看看我的客户端代码然后我会告诉你我的问题:
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
sentence = inFromServer.readLine();
System.out.println("Response from Server : " + sentence);
if (sentence.equals("available")){
BufferedReader inFromServer1 = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while ((sentence = inFromServer1.readLine()) != null) {
myJob = myJob + sentence ;
}
inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String acception = inFromServer.readLine();
if (acception.equals("accepted")){
File file = new File("account.json");
byte[] bytes = new byte[2048];
InputStream inputStream = new FileInputStream(file);
OutputStream outputStream = clientSocket.getOutputStream();
int count;
try {
while ((count = inputStream.read(bytes)) > 0){
outputStream.write(bytes, 0, count);
}
outputStream.close();
inputStream.close();
}catch (IOException io){}
continue;
}else if (acception.equals("notaccepted")){
continue;
}
现在,我的问题是当我运行我的服务器然后运行我的客户端时,我的服务器将在不等待我的客户端获取输入流的情况下运行。首先,客户获得"可用"但是当客户端到达第二个getInputStream时,服务器会调整OP-WRITE注册的所有阶段并等待客户端获取数据流(正如我在代码中定义的那样)。 实际上,我的服务器做得很好。它将按所需顺序通过所有阶段。但问题是发送和接收数据不是同步的。 我不知道我的问题是什么。但我想当我连续注册OP-WRITE时,这意味着我的服务器没有发送所有字节的数据,所以只有第一个getInputStream才能获得数据。 另一方面,我需要这个命令来运行我的程序。那么,有什么想法吗?
答案 0 :(得分:0)
我发现了我的问题。我的代码没有问题。任何订单随时都可以注册OP_WRITE。最重要的是写入缓冲区并正确读取套接字。 实际上,当我第二次向我的客户发送东西时,我没有清除缓冲区。在这种情况下,我发现它,并纠正它。 但是当我向客户端发送一些字符然后想要发送文件时,因为在我的客户端,我有一个循环来获取所有字符,如果文件是通过相同的循环得到的内容。 这里的问题是我如何将它们分开?
答案 1 :(得分:-1)
在考虑模式之前,我会帮助您澄清问题:
您有一个线程/进程传递一条消息,要求另一个线程/进程对该消息进行操作。
接收方需要读取消息并可能启动它自己的一些子线程来执行该工作,因为它可以接收其他请求。
告诉发件人确认收到了请求会很高兴。
似乎有必要保护消息传递。因为如果您在阅读时遇到其他请求,您最终可能会处理垃圾。
您可以将nio配置为具有多个读取器和一个编写器,只需读取缓冲区的一部分等。检查how-tos,api docs。这是非常强大的
答案 2 :(得分:-1)
发送消息后
TCP中没有消息。它是一个字节流。发送方的两次写入很可能是通过接收方的一次读取来读取的。如果你想要消息,你必须自己实现它们,包括计数字,终结符,STX / ETX,XML等。