我遇到套接字问题。当我在同一台PC上运行服务器和客户端时,即使用" localhost"参数。但是,当使用不同的PC时,看不到问题。 客户端使用以下代码发送文件:
output_local.write(buffer, 0, bytesRead);
output_local.flush();
然后在另一种方法中,我发送了一个命令:
outputStream.write(string);
outputStream.flush();
服务器将命令附加到文件末尾。所以它认为它还没有从客户端收到命令。你知道可能导致这个问题的原因吗?我该如何解决这个缺陷?下面是服务器上的文件接收方法:
while (true) {
try {
bytesReceived = input.read(buffer);
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("exception occured");
break;
}
System.out.println("received:" + bytesReceived);
try {
/* Write to the file */
wr.write(buffer, 0, bytesReceived);
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
total_byte = total_byte + bytesReceived;
if (total_byte >= filesizeInt) {
break;
}
}
答案 0 :(得分:7)
如果您需要类似消息的支持,则需要创建一个协议来阐明您要发送和接收的内容。
在TCP中,您不能依赖单独接收的单独“数据包”(例如,发送4个10字节的块可以作为1个40块接收,或者2个块中的20个接收,或者一个39块接收1)的一大块。 TCP保证订单交付,但不保证数据的任何特定“打包”。
因此,例如,如果您要发送字符串,则需要先发送字符串长度,然后再发送字节。伪代码中的逻辑类似于:
<强>客户端:强>
服务器强>
答案 1 :(得分:5)
缺点是您正在将基于流的协议(TCP)视为面向消息的协议。不是。你应该假设这可能发生。
如果您需要将流分成单个消息,则应为每条消息使用分隔符或(最好是IMO)长度前缀。您还应该预期任何读取您的问题可能无法获得您所要求的数据 - 换句话说,如果您不小心,不仅可以合并消息,而且可以容易分裂。
我提到我更喜欢使用长度前缀来分隔符。利弊:
答案 2 :(得分:3)
由于TCP是面向流的连接,如果编写器写入速度比读取器读取速度快,或者TCP堆栈发送数据包,则此行为是正常的。
您应该添加一个分隔符来分隔流的各个部分,例如通过对子数据包使用长度字段,或使用换行符(如换行符\n
,字符代码10)。
另一种选择可能是使用UDP(甚至是SCTP),但这取决于要完成的任务。