working with TCP/IP

  • Thread starter Thread starter Logan McKinley
  • Start date Start date
L

Logan McKinley

I have a client server application where the client sends mouse movements
and text to the server like "MVU 15" would move the mouse up 15 pixels and
"CHAR a" would send an 'a' to the current application. The problem I am
having is that when I try to send a string of chars I get multiple sends
when I read from the TCP/IP stream for instance on one read I might get
"CHAR aCH" then the next read I will get "AR bCH" which obviously breaks my
code.
I am using the following code to send the data
---------------------------
System.IO.StreamWriter NStream;
client = new System.Net.Sockets.TcpClient();
client.Connect(System.Net.IPAddress.Parse(strIPAddress),6254);
NStream = new System.IO.StreamWriter(client.GetStream());
NStream.Write(s);
NStream.Flush();
---------------------------
and the following to read the data
---------------------------
skt = listener.AcceptSocket();
byte[] b = new byte[15];
res = skt.Receive(b);
----------------------------------------

I was thinking i will pad the data to 15 chars but it doesn't seem to be a
problem for most things, but that might have been a result of the speed it
was sent.

Any ideas would be great.
Thanks in advance,
~Logan
 
Logan McKinley said:
I have a client server application where the client sends mouse movements
and text to the server like "MVU 15" would move the mouse up 15 pixels and
"CHAR a" would send an 'a' to the current application. The problem I am
having is that when I try to send a string of chars I get multiple sends
when I read from the TCP/IP stream for instance on one read I might get
"CHAR aCH" then the next read I will get "AR bCH" which obviously breaks my
code.
I am using the following code to send the data
---------------------------
System.IO.StreamWriter NStream;
client = new System.Net.Sockets.TcpClient();
client.Connect(System.Net.IPAddress.Parse(strIPAddress),6254);
NStream = new System.IO.StreamWriter(client.GetStream());
NStream.Write(s);
NStream.Flush();
---------------------------
and the following to read the data
---------------------------
skt = listener.AcceptSocket();
byte[] b = new byte[15];
res = skt.Receive(b);
----------------------------------------

I was thinking i will pad the data to 15 chars but it doesn't seem to be a
problem for most things, but that might have been a result of the speed it
was sent.


Yes you have to define a protocol on top of TCP/IP to do this. If you look
at Telnet, HTTP, etc you will see various solutions to this problem.

Common solutions include fixed-size transmissions (like you suggested),
putting a special character at the end of each message (eg a newline), or
sending a fixed-width header containing the length of the rest of the
message.

Oh, and you need to Receive in a loop. Receive is not guaranteed to block
until your buffer is full. So you may not get all 15 bytes in the first
call (although with small buffers you typically will).

byte[] b = new byte[bufSize];
for (int br = 0; br < bufSize;)
{
br += skt.Receive(b,br,bufSize-br);
}



David
 
Hi,

Logan McKinley said:
I have a client server application where the client sends mouse movements
and text to the server like "MVU 15" would move the mouse up 15 pixels and
"CHAR a" would send an 'a' to the current application. The problem I am
having is that when I try to send a string of chars I get multiple sends
when I read from the TCP/IP stream for instance on one read I might get
"CHAR aCH" then the next read I will get "AR bCH" which obviously breaks my
code.
I am using the following code to send the data
---------------------------
System.IO.StreamWriter NStream;
client = new System.Net.Sockets.TcpClient();
client.Connect(System.Net.IPAddress.Parse(strIPAddress),6254);
NStream = new System.IO.StreamWriter(client.GetStream());
NStream.Write(s);
NStream.Flush();
---------------------------
and the following to read the data
---------------------------
skt = listener.AcceptSocket();
byte[] b = new byte[15];
res = skt.Receive(b);
----------------------------------------

I was thinking i will pad the data to 15 chars but it doesn't seem to be a
problem for most things, but that might have been a result of the speed it
was sent.

This is ussaly the first problem one encounter with tcp. It's however the
design of tcp. You never know how much bytes you can receive.

The solution most tcp server/client use, is to use a delimiter. So after
you send each command you add e.g. "\r\n".

Some pseudo code:

client = new System.Net.Sockets.TcpClient();
client.Connect(System.Net.IPAddress.Parse(strIPAddress),6254);
NetworkStream ns = client.GetStream();

void SendCmd ( string cmd )
{
// check if cmd is valid, size, etc,

byte[] buf = Encoding.UTF8.GetBytes( cmd + "\r\n");

ns.Write ( buf, 0, buf.length )
}

On the receiving site, you do a receive loop

void Receive()
{
Text.UTF8Encoding enc = new Text.UTF8Encoding();
byte buf[] = new byte[1024];
StringBuilder recvqueue = new StringBuilder();
int n; // bytes received
// Read only returns 0 if the remote site has closed gracefully,
// if there's nothing to read, it blocks until there is...
while( (n=ns.Read( buf, 0, buf.length ) > 0 )
{
// append partial reads to queue
recvqueue.Append( enc.GetString( buf, 0, n ) );

// check if the queue contains full messages (ending on \r\n)
// for each message call a ProcessCommand
int rn;
while ( (rn=recvqueue.ToString().IndexOf("\r\n"))!=-1 )
{
ProcessCommand( recvqueue.ToString().Substring(0, rn) );
recvqueue.Remove(0, rn + 2);
}
}
}

void ProcessCommand( string command)
{
/// do someting with the received command
}

This is not complete, just to get you going, other problems arise, like when
receiving in a loop, you need an extra thread or use asnyc calls, maybe the
queue could be optimized, etc...

And off course error checking. Read may throw things.

Hope this helps
Greetings
 
Back
Top