客户端/服务器应用程序 - 丢失字节

5

我用Java创建了一个客户端,想要向我的C#服务器发送一些数据。

问题在于,如果我在客户端中写入例如“hello”,我只收到第一个字母。在字节数组中只有一个元素。

我猜测问题出在服务器端,因为在我的Java服务器上一切正常,所以Java客户端也可以正常工作。

有人看到任何问题吗?

提前谢谢。


1
你调试过了吗,以确定 k 是否大于 1? - Lews Therin
K = 1。如果我理解正确的话,它应该是字节数组中有多少个元素。但由于只有一个元素,所以k = 1。 - Jakub
发送数据后尝试刷新输出流。 - Lews Therin
3个回答

3

你对TCP的理解有误,你不仅仅“接收”一次就能得到一次“发送”的结果。

TCP是一种“流式”协议,不会自动分成“数据包”。甚至在一个receive中,你可能会得到两个不同的send的数据。

常见的做法是在消息前加上其长度,这样你就可以调用接收函数直到获取所需的字节数。为了使接收函数在缓冲区没有数据时立即返回,请将套接字设置为非阻塞

这篇文章也讲得很好。

现在,你提供的代码应该可以正常工作,因为本地网络几乎没有延迟。你是否检查过Java部分是否缓冲数据流/是否可以手动刷新它们?


3
正如Damon Gant所说,TCP是一种流式协议。我建议您创建自己的协议。不要发送字符串。如果您正在进行任何非平凡操作,则这真的是最佳选择。
通常在我的协议头中包括魔术数字、校验和、数据包体长度以字节为单位和协议版本。魔术数字使得在流中界定数据包更容易(对于调试您的自定义协议流非常有用)。具有校验和可以帮助确保正确解析事物。由于TCP协议已经具有校验和,因此校验和在TCP上并没有太大的帮助。数据包体长度可以帮助您检测是否有所有数据包的字节。协议版本可以帮助您知道如何解释数据包体的字节。
收到数据后,请将所有字节放入单独的缓冲区并扫描您的协议头。如果您可以解析协议头,请检查该数据包的字节是否全部存在。如果是,则解析该数据包。重复此过程,直到找到不完整的数据包或缓冲区为空。
对于要发送的每个数据包,请创建一个类。当您要发送数据包时,请创建并序列化适当的类,并在该类的字节前添加您的协议头。
您可以使用Java的序列化程序,但是如果许多客户端连接到单个服务器,则可能不希望使用Java作为服务器。这使得事情变得困难,因为现在您需要在另一种语言中实现Java序列化程序。因此,更好的方法通常是手动将数据包转换为字节(繁琐但简单),或者您可以使用反射编写自己的序列化程序。对于较大的项目,我建议后者。

2

问题可能在Java端,因为您的监听器正常工作。 我将您的监听器代码复制粘贴到测试应用程序中。 然后我创建了另一个测试应用程序并发送了“hello world”,我完全听到了它。

public static  void sender()
{
  TcpClient client = new TcpClient();
  IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.236"), 30000);
  client.Connect(serverEndPoint);
  NetworkStream clientStream = client.GetStream();
  ASCIIEncoding encoder = new ASCIIEncoding();
  byte[] buffer = encoder.GetBytes("Hello Server!");

  clientStream.Write(buffer, 0, buffer.Length);
  clientStream.Flush();
}


Connection accepted from 192.168.2.236:22811
Recieved...
Hello Server!

顺便提一下,这可能是更好的监听器。

public void listener()
    {
  TcpListener tcpListener = new TcpListener(IPAddress.Any, 30000);
  tcpListener.Start();

  TcpClient tcpClient = tcpListener.AcceptTcpClient();
  NetworkStream clientStream = tcpClient.GetStream();

  byte[] message = new byte[4096];
  int bytesRead;

  while (true)
  {
    bytesRead = 0;

    try
    {
      //blocks until a client sends a message
      bytesRead = clientStream.Read(message, 0, 4096);
    }
    catch
    {
      //a socket error has occured
      break;
    }

    if (bytesRead == 0)
    {
      //the client has disconnected from the server
      break;
    }

    //message has successfully been received
    ASCIIEncoding encoder = new ASCIIEncoding();
    Console.Write(encoder.GetString(message, 0, bytesRead));
  }

  tcpClient.Close();
}

谢谢!这个监听器有效。即使我仍然不明白为什么之前那个没有起作用。 - Jakub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接