我在使用tcp socket发送数据包时遇到问题。我的程序做的非常简单:首先,客户端套接字连接到服务器套接字。然后服务器套接字发送5"你好"回到客户端,客户端输出5"你好"到控制台。客户端和服务器都在我的本地计算机上运行,下面是完整的代码:
服务器
public class Server {
private static ServerSocket serverSocket;
public static void main(String[] args) throws IOException, InterruptedException {
serverSocket = new ServerSocket(60009);
serverSocket.setReuseAddress(true);
System.out.println("Server started!");
final Socket socket = serverSocket.accept();
socket.setTcpNoDelay(true);
Thread.sleep(1000);
socket.getOutputStream().write("hello".getBytes());
socket.getOutputStream().write("hello".getBytes());
socket.getOutputStream().write("hello".getBytes());
socket.getOutputStream().write("hello".getBytes());
socket.getOutputStream().write("hello".getBytes());
InputStream is = socket.getInputStream();
is.read(new byte[100]);
}
}
客户端:
public class Client {
static Socket socket;
static byte[] buffer;
public static void main(String[] args) throws IOException {
socket = new Socket();
socket.setTcpNoDelay(true);
socket.connect(new InetSocketAddress("localhost", 60009));
buffer = new byte[100];
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
InputStream is = null;
try {
is = socket.getInputStream();
is.read(buffer);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String rcvStr = new String(buffer);
System.out.println(rcvStr);
}
}
}).start();
}
}
鉴于上面发布的代码,我的预期输出应该是这样的:
您好
您好
您好
您好
您好
但是,我得到的实际结果是:
您好
hellohellohellohello
我的问题就在这里。结果输出不遵循我在服务器上发送的顺序。我要求服务器发送5"你好"逐一。但根据结果,似乎服务器真正做的是发送一个"你好"起初然后发送剩余的四个"你好"一起来。
搜索谷歌后,我发现很多人将这个问题与所谓的Nagle算法联系起来,这将避免tcp套接字立即发送短数据包以提高网络使用效率。要禁用Nagle算法,只需要在socket上调用setTcpNoDelay(true)。然后,计算机将立即发送您要求发送的任何内容。但不幸的是,在我禁用Nagle算法后,我的客户端仍然输出与上面相同的结果。你能告诉我我错过了什么或做错了吗?非常感谢任何帮助!
答案 0 :(得分:1)
我可以重现你所看到的行为。但是,这可能会令你失望,Nagle算法与此处发生的事情毫无关系。
当您运行客户端和服务器,并使用struct top_level_module: private module0, private module1 {
using module0::a;
using module0::b;
using module0::c;
using module1::d;
using module1::e;
};
检查网络流量时,您可以看到每次调用tcpdump
都会生成一个包含字符串write
的TCP数据包。当您拨打hello
和不拨打电话时,会发生这种情况。总而言之,发件人的工作方式与预期完全相同:您正在写入无缓冲的setTcpNoDelay(true)
,并且数据会立即发送出去。
因此,您一次读取四个数据包的原因是因为数据包在接收端缓冲。我认为你无能为力。如果您需要区分TCP流中的连续消息,则需要查看各种serialization算法。
答案 1 :(得分:0)
您应该使用缓冲的读取器和写入器,用newLine分隔每条消息,并使用读取器读取每一行:
首先,设置您的流:
std::string
然后通过调用如下函数在服务器上写消息:
bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bufferedWriter.flush();
然后在客户端上,读取像这样的行:
private void rawSend(final String rawText) throws IOException {
bufferedWriter.write(rawText);
bufferedWriter.newLine();
bufferedWriter.flush();
}