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

时间:2012-10-28 18:28:01

标签: c# java sockets

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

问题是如果我在客户端写例如你好,我只得到第一个字母。在字节数组中只有一个元素。

我想服务器端存在一些问题,因为在我的JAVA服务器中工作正常,所以JAVA中的客户端工作正常。

有人看到任何问题吗?

提前谢谢。

3 个答案:

答案 0 :(得分:3)

你正在考虑TCP的错误方法,你不只是“接收”一次并得到一个“发送”的结果。

TCP是一种“流”协议,不会自动分成“数据包”。您甚至可以在一次接收中获得2个发送的数据。

一种常见的模式是为一条消息添加长度前缀,因此您可以调用receive,直到获得所请求的字节数。如果缓冲区中没有数据,则立即返回Receive,set your socket to non-blocking

Here's another good article on the topic.

现在,您提供的代码应该以任何一种方式工作,因为本地网络上几乎没有延迟。您是否检查过Java部件是否缓冲蒸汽/是否可以手动冲洗它们?

答案 1 :(得分:3)

正如Damon Gant所说,TCP是一种流媒体协议。我建议你创建自己的协议。我不会发送字符串。如果你正在做任何非平凡的事情,这真的是最好的方式。

通常,我在协议标头中包含幻数,校验和,数据包主体长度和协议版本。神奇的数字可以更容易地描述流中的数据包(对调试自定义协议流非常有用。)拥有校验和有助于确保正确解析事物。校验和对TCP的完整性没有多大帮助,因为TCP协议已经有校验和。数据包主体长度可帮助您检测何时包含数据包的所有字节。协议版本可以帮助您了解如何解释数据包正文的字节。

接收数据后,将所有字节放入单独的缓冲区并扫描您的协议标头。如果您可以解析标头,请检查数据包的字节是否全部存在。如果是,请解析数据包。重复此过程,直到找到不完整的数据包,或缓冲区为空。

对于您要发送的每个数据包,我都会创建一个类。如果要发送数据包,请创建并序列化正确的类,并为该类的字节前缀协议标头。

您可以使用Java的序列化程序,但如果您有许多客户端连接到单个服务器,您可能不希望将Java用于服务器。这使事情变得困难,因为现在你需要用另一种语言实现java序列化器。因此,通常可以手动将数据包转换为字节(繁琐但简单),或者您可以使用反射编写自己的序列化程序。我建议后者用于更大的项目。

答案 2 :(得分:2)

问题在java方面是可行的,因为你的监听器工作正常。 我将您的监听器代码复制粘贴到测试应用程序中。 比我创建另一个测试应用程序并发送问候语,我完全听了。

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();
}