Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Client/Server App - Losing bytes

Tags:

java

c#

sockets

I created a client in Java and I want simply to send some data to my server that is in C#.

The problem is that if I write in the client for example hello, I get only the first letter. In the byte array there is only one element.

I guess there is some problem with the server side because in my server in JAVA works everything fine so the client in JAVA works fine.

Does anybody see any problem?

Thank you in advance.

like image 770
Jakub Avatar asked Oct 28 '12 18:10

Jakub


3 Answers

You're thinking about TCP the wrong way, you don't simply "Receive" once and get the result of one "Send".

TCP is a "streaming" protocol and does not automatically separate into "packets". You may even get data of 2 sends in one receive.

A common pattern is to prefix one message with its length, so you can call receive until you get the amount of bytes requested. To make Receive return immediately if no data is in the buffer, set your socket to non-blocking.

Here's another good article on the topic.

Now, your provided code should work either way because there is next to no latency on local networks. Have you checked if your Java part buffers steam / can you manually flush them?

like image 132
Aurelia Avatar answered Oct 03 '22 21:10

Aurelia


As Damon Gant said, TCP is a streaming protocol. I suggest you create your own protocol. I wouldn't send strings. If you're doing anything non-trivial this is really the best way to go.

Typically I include a magic number, checksum, packet body length in bytes, and protocol version in my protocol headers. The magic number makes it easier to delineate packets in a stream (very useful for debugging your custom protocol stream.) Having a checksum helps ensure you're parsing things correctly. A checksum doesn't help much with integrity over TCP as the TCP protocol already has a checksum. The packet body length helps you detect when you have all the bytes for your packet. The protocol version can help you know how to interpret the packet body's bytes.

Upon receiving data, place all bytes into a separate buffer and scan for your protocol header. If you can parse your header, check to see that packet's bytes are all present. If so, parse the packet. Repeat this process till you find an incomplete packet, or the buffer is empty.

For each packet you want to send, I'd create a class. When you want to send a packet, create and serialize the proper class, and prepend your protocol header for that class's bytes.

You could use Java's serializer, but if you've many client's connecting to a single server, you probably don't want to use Java for the server. This makes things difficult because now you need to implement a java serializer in another language. Because of this its typically better to either convert your packets into bytes by hand (tedious but simple,) OR you could write your own serializer using reflection. I'd suggest the latter for bigger projects.

like image 27
William Morrison Avatar answered Oct 03 '22 23:10

William Morrison


problem is prabably in java side because your listener works fine. I copy pasted your listener code in a test application. Than I created another test applicationand send hello word and I listened it completely.

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!

Btw, this might be better listener.

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();
}
like image 27
Nesim Razon Avatar answered Oct 03 '22 21:10

Nesim Razon