in this qusetion C# Receiving Packet in System.Sockets
a guy asked:
"In my Client Server Application i wondered how to make a packet and send it to the server via the Client
Then on the server i recognize which packet is this and send the proper replay"
and showed the example of his way of implementing the 'packet recognizer'. He got an answer that his way of 'structuring the message' is bad, but no explanation and code example followed by the answer.
So please, can anybody show the example of a good code, which should do something like this, but proper way:
[client]
Send(Encoding.ASCII.GetBytes("1001:UN=user123&PW=123456")) //1001 is the ID
[server]
private void OnReceivePacket(byte[] arg1, Wrapper Client)
{
try
{
int ID;
string V = Encoding.ASCII.GetString(arg1).Split(':')[0];
int.TryParse(V, out ID);
switch (ID)
{
case 1001://Login Packet
AppendToRichEditControl("LOGIN PACKET RECEIVED");
break;
case 1002:
//OTHER IDs
break;
default:
break;
}
}
catch { }
}
TCP ensures that data arrives in the same order it was sent - but it doesn't have a concept of messages. For instance, say you send the following two fragments of data:
1001:UN=user123&PW=123456
999:UN=user456&PW=1234
On the receiving end, you will read 1001:UN=user123&PW=123456999:UN=user456&PW=1234 and this might take one, two or more reads. This may even arrive in two packets as:
1001:UN=user123&PW=12
3456999:UN=user456&PW=1234
This makes it very had to parse the message correctly. The other post mentions sending the length of a packet before the actual data, and that indeed solves the problem, as you can determine exactly when one message ends and the next starts.
As an example, client and server could agree that each message starts with 4 bytes containing the length of the message. The receiver could then simply:
load 4 bytes exactly
convert to an integer, now you know the length of the remainder of the message
read exactly that many bytes and parse the message
C# conveniently has the BitConverter class that allows you to convert the integer to a byte[] and vice versa.
Related
I'm stuck at the concept of TCP as a stream-oriented protocol.
While using Sockets or anything that uses that protocol there is no way to know how much data will be received in a single receive; so for example if we send 1024 bytes, it can be received in 3 Receive methods give or take.
So we basically need to keep calling our receive methods until the buffer hits the size sent.
I'm still struggling on network, I'm trying to get a bit comfortable using Client/Server applications. I found that the easiest way to do so is to create packets and send them over the network.
So my question is: When serializing a Class as a packet that has - lets say a typeof Normal.Message - and has a string that holds the Message...
[Serializable]
Class Message
{
String Msg;
public Message(String msg)
{
This.Msg = msg;
}
}
...if we sent this packet, is it undetermined that it will be received in one Receive Method? And if not, what's the easiest way to ensure that it will?
My Context
I have a TCP networking program that sends large objects that have been serialized and encoded into base64 over a connection. I wrote a client library and a server library, and they both use NetworkStream's Begin/EndReadandBegin/EndWrite. Here's the (very much simplified version of the) code I'm using:
For the server:
var Server = new TcpServer(/* network stuffs */);
Server.Connect();
Server.OnClientConnect += new ClientConnectEventHandler(Server_OnClientConnect);
void Server_OnClientConnect()
{
LargeObject obj = CalculateLotsOfBoringStuff();
Server.Write(obj.SerializeAndEncodeBase64());
}
Then the client:
var Client = new TcpClient(/* more network stuffs */);
Client.Connect();
Client.OnMessageFromServer += new MessageEventHandler(Client_OnMessageFromServer);
void Client_OnMessageFromServer(MessageEventArgs mea)
{
DoSomethingWithLargeObject(mea.Data.DecodeBase64AndDeserialize());
}
The client library has a callback method for NetworkStream.BeginRead which triggers the event OnMessageFromServer that passes the data as a string through MessageEventArgs.
My Problem
When receiving large amounts of data through BeginRead/EndRead, however, it appears to be fragmented over multiple messages. E.G. pretend this is a long message:
"This is a really long message except not because it's for explanatory purposes."
If that really were a long message, Client_OnMessageFromServer might be called... say three times with fragmented parts of the "long message":
"This is a really long messa"
"ge except not because it's for explanatory purpos"
"es."
Soooooooo.... takes deep breath
What would be the best way to have everything sent through one Begin/EndWrite to be received in one call to Client_OnMessageFromServer?
You can't. On TCP, how things arrive is not necessarily the same as how they were sent. It the job of your code to know what constitutes a complete message, and if necessary to buffer incoming data until you have a complete message (taking care not to discard the start of the next message I the process).
In text protocols, this usually means "spot the newline / nul-char". For binary, it usually means "read the length-header in the preamble the the message".
TCP is a stream protocol, and has no fixed message boundaries. This means you can receive part of a message or the end of one and the beginning of another.
There are two ways to solve this:
Alter your protocol to add end-of-message markers. This way you continuously receive until you find the special marker. This can however lead that you have a buffer containing the end of one message and the beginning of another which is why I recommend the next way.
Alter protocol to first send the length of the message. Then you will know exactly how long the message is, and can count down while receiving so you won't read the beginning of the next message.
I have an Arduino microcontroller with a Sparkfun WiFly shield.
I build a simple program in C#/.NET that connects to the Arduino using System.Net.Sockets:
Socket Soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void SendMsg(string msg)
{
try
{
byte[] buffer = StrToByteArray(msg);
if (Soc.Connected)
Soc.Send(buffer);
else
{
Soc.Connect(this.remoteIP);
Soc.Send(buffer);
}
}
catch (Exception e){}
}
On the arduino I have:
while(SpiSerial.available() > 0) {
byte b = SpiSerial.read();
Serial.println(b);
}
When a socket connection does a handshake, I get: "*OPEN*" and when closed, I get: "*CLOS*".
The problem is that I get the messages one byte by another and sometimes I don't get the full message on one while loop.
So if I use the code I showed above on the Arduino, my serial terminal looks like:
*
O
P
E
N
*
T
E
S
T
*
C
L
O
S
*
So how can I figure out the message the PC is trying to send?
I know I need somehow to use a special byte that will symbolise the end of my message. (A special byte that I won't use in my message, only to symbolise the end of a message)
But how can I do it? And which byte to use?
You need to design your own protocol here. You should define a byte (preferably one that won't occur in the data) to indicate "start", and then you have three choices:
follow the start byte with a "length" byte indicating how much data
to read
define an "end" byte that marks the end of your data
read data until you have a complete message that matches one of
the ones you expect
The third option is the least extensible and flexible, of course, as if you already have a message "OPEN" you can't then add a new message "OPENED" for instance.
If you take the second option and define an "end" byte then you need to worry about escaping that byte if it occurs within your data (or use another byte that is guaranteed not to be in your data).
Looking at your current example, a good starting point would be to simply prefix each message with a length prefix.
If you want to support long messages you can use a 2 byte length prefix, then you read the first 2 bytes to get the length and then you continue reading from the socket until you have read the number of bytes indicated by the length prefix.
Once you have read a complete message you are then back to expecting to read the length prefix for the next message and so on until the communication is terminated by one of the parties.
Of course in between all this you need to check for error conditions like the socket on one end being closed prematurely etc. and how to handle the potential partial messages that can result form the premature closing of the socket.
I am sending and receiving bytes between a server and a client. The server regularly sends some message in the form of bytes and client receives them.
Message format is below:
{Key:Value,Key:Value,Key:Value}
Now at the client side instead of receiving this message, I am receiving multiple copies of this message which is not suitable for this.
The client is receiving like this:
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,
Can someone help me figure out the problem?
Updated
This code is sending instructions.
var client = (param as System.Net.Sockets.Socket);
while (true)
{
try
{
var instructions = "{";
instructions += "Window:" + window + ",";
instructions += "Time:" + System.DateTime.Now.ToShortTimeString() + ",";
instructions += "Message:" + msgToSend + "";
instructions += "}";
var bytes = System.Text.Encoding.Default.GetBytes(instructions);
client.Send(bytes, 0, bytes.Length, System.Net.Sockets.SocketFlags.None);
}
catch (Exception ex)
{
continue;
}
}
This code is receiving at client side.
while (true)
{
try
{
var data = new byte[tcpClient.ReceiveBufferSize];
stream.Read(data, 0, tcpClient.ReceiveBufferSize);
instructions = System.Text.Encoding.Default.GetString(data.ToArray());
}
catch (Exception ex)
{
continue;
}
}
Okay, a few problems with this code:
You're using Encoding.Default, which is almost certainly not what you want to do
You're always decoding the whole string, rather than just the amount you've actually managed to read - you're ignoring the return value of stream.Read
You're just continuing after an exception, with no logging, error handling or anything
As Dean says, you're repeatedly sending the same data
Ideally, it would be useful for your messages to have a prefix saying how long each one is, in bytes. Then in the receiving side you can read that length, then loop to repeatedly read into a buffer until you've read all the data you need. Then perform the decoding.
If you can't change the protocol, you'll still need to loop round, but checking for the end delimiter ("}" presumably) explicitly - and noting that you may receive data from the next message which you'll have to store until you next want to read.
You've got:
while (true)
In the sender: it's just going to keep sending the same thing over and over...
Also, if you get an exception trying to send or receive the data, you can't just try again and expect it to work. Depending on the exact error, you might need to reestablish the connection, or it might be that the network has gone away completely. In any case, simply retrying again is almost always going to be the wrong thing to do.
Problem has figured out like Dean Harding said.
But beside you should be more clearly about "client" or "server".
Basicaly:
Only server side should wait (by a loop) for msgs. Client (sender) sends msgs when needed or in condition.
You can sending msg in loop but should control and regulate it by a "Sleep" or "Timer". In this way, you can spare resource and give more time for receiver can process msg completely.
Your are sending your data through TCP. TCP is a stream-oriented protocol, so you know the client will receive the same stream of bytes in the same order, but you loose the packet boundaries. Your protocol seems to be packet-oriented instead. Then you have the choice:
switch to a packet-oriented protocol (UDP) or
delimit the packets yourself at the receiving side (as Jon Skeet said, by looking for the delimiters).
Keep in mind that TCP has some reliability features not found in UDP. If reliability is not a concern, switch to UDP. Otherwise, finding the delimiters at the client side should be easier than implementing your own reliability layer.
My application in c# wants to cominicate with 3rd party Tcp server to send data and recieve back response messages ...The syntax of commands has UShort,ULONG,BYTE type datas
a sample command that needed to send by my app is
USHORT 0xFFFF
USHORT 0x00D0
BYTE 0xDD
then in app i send data as
TcpClient tcpClient = new TcpClient();
tcpClient.Connect("XX.XX.XX.XX",portnumber);
Networkstream ns=tcpClient.GetStream();
StreamWriter sw=new StreamWriter(ns);
sw.Write(0xFFFF);
sw.Write(0x00DD);
sw.Write(0x00);
//or send them bytes
sw.Write(0xFF);
sw.Write(0xFF);
sw.Write(0x00);
sw.Write(0xD0);
sw.Write(0x00);
sw.Write(0x00);
and I read incoming messages over server as
while (true)
{
byte[] buff=new byte[tcpClient.ReceiveBufferSize];
ns.Read(buff, 0, tcpClient.ReceiveBufferSize);
string dv= BitConverter.ToString(buff));
}
//returned data looks like FF-A2-00-23-00-02-00-00-00-00-00-00-D9-2E-20-2E-00-A0-04-00-AE-08
//yes i know this byte syntaxes but returning data is not that i look response for command that i sent..
but returning values are not that i look for
Is there any wrong on my code with sending data to server??
and any recomendations on reading writing datas are welcome...
Nobody can tell you what's wrong with the response when they don't know the protocol employed. The server's sending that because it feels like it... it might be something wrong with your request, or it might be a message indicating that it's offline for service. You can only check it's specification on how to interpret the result it did send, or ask the people who maintain it.
Might also be a good idea to tag this question with the language you're using, so people can make sense of the function calls and whether you're invoking them properly.
I'd also recommend using a packet sniffer (or on Linux simply strace) to show the packets being read and written... you will probably see the mistakes there. Then, use another program to interact with the server that does work, and compare bytes.