tags:

views:

748

answers:

2

I have this bit of code that is receiving a series of messages:

byte[] buffer = new byte[10240];
//...
sock.Receive(buffer);
string response = message(buffer);
Console.WriteLine("Message Recieved");
if (!verifyUser(response, sock))
Console.WriteLine("User Invalid");
//...
static private bool verifyUser(string userString, Socket sock)
{
   string[] userData = userString.Split(' ');
   int i = 0;
   while (true)
    {
        if (userData[0].ToUpper() != "USER")
        {
           byte[] buffer = message("WHO");
           sock.Send(buffer);
           userData = userString.Split(' ');
           i++;
           if (i > 4)
           {
                        return false;
                    }
                    continue;
                }
                else
                    break;
            }
Console.WriteLine("Connection recieved from " + userData[1] + " with hash of "/* + userData[2]*/);
}

The problem I'm having is that if I submit the username unkwntech all that gets displayed it unkwnt, and the second value never seems to get there. the app sending the data looks like this:

static void Main(string[] args)
        {
            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
            EndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 200);
            sock.Connect(remoteEP);
            byte[] buffer = Encoding.ASCII.GetBytes("USER unkwntech a3f5h4a35sfg");//Made up hash
            sock.Send(buffer);
            sock.Receive(buffer);
            Console.WriteLine(Encoding.ASCII.GetString(buffer));
            Console.ReadLine();
        }
+6  A: 

You're assuming that when you send, all the data ends up in a single packet, and that you'll receive all the data in one go on the other end. That's not how TCP/IP works. It's a streaming protocol - you should never make assumptions about how much data you'll receive at a time.

Basically you need to read from the stream until either you've read all the data and the socket has been closed, or until you've got "enough" data. If you're in control of the protocol and it's a conversational protocol, it makes life a lot easier if each message you send is prefixed by its length - it means the other end knows how much data to expect.

Jon Skeet
+1  A: 

Check the return value of your Socket.Receive call. It returns the number of bytes received. You can put this call in a loop and read until you get the number of bytes you're expecting. You should also guard against infinite looping by setting a max number of tries, or as John suggested, checking the status of the socket. Also, don't assume a return value of zero means you've read the whole message.

If your protocol has each message prefixed by its length, to be really bullet-proof your protocol should also define a marker byte to mark the end of the prefixed length header. Read one byte at a time until you see the marker byte. Then calculate the length of the message and read in larger chunks until you've read it all.

Socket.Receive defines an overload that lets you specify how many bytes you want to receive. (However, you're not guaranteed to receive that many, so you still have to check the return value.)