C# Socket Receive messes up data - c#

I am trying to create a client/server application which communicates through Sockets. But when I receive data it randomly messed up and does not always (sometimes) show the correct data. The code I use to receive data:
private static void ReceiveCallback(IAsyncResult AR)
{
try
{
Socket socket = (Socket)AR.AsyncState;
if (SocketConnected(socket))
{
int received = socket.EndReceive(AR);
byte[] dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
string text = Encoding.ASCII.GetString(dataBuf);
if (!text.Contains("GET") && !text.Contains("HTTP") && text != null)
{
Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + ":" + text);
}
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
}
}
catch
{
}
}
can someone explain me why this happends? Thanks in advance!
Also, I have tried to check untill it finds a character (which is on the end of every response '-' but that did not work). Unfortunatley this was the result:

I assume your socket is a TCP socket, since you're dealing with something like HTTP.
TCP deals with streams, not messages. So when you do your read, at most _buffer.Length bytes are read from the stream. This means that you can easily read just a part of the response - or rather, the response will be split between multiple callbacks. When you read enough by chance, everything works as expected. This is especially true when testing on localhost, because Windows treats localhost TCP very differently from the non-localhost case. But when it so happens that you don't read enough, text will not contain the whole response - and your data is broken.
Additionally, when received is zero, it means the other side has closed the stream and you should stop doing BeginReceive.

You have to loop on the socket receive until you get your entire message.
This also means that you must have an application level protocol. What defines a message?
A termination character? Then loop on the read until you get that character.
A count of characters? Then loop on the read until you get that many characters.
Is the length of the message at the front of the message? Then loop until you get enough bytes to get the length, then loop until you get the entire message.

Your socket code looks fine to me. Characters encoding format in the .Net world is "Unicode", you should convert the bytes you receive to Unicode instead of ASCII :
string text = Encoding.Unicode.GetString(dataBuf);

Related

C# TCP server receives two messages send by Python client at once

I am trying to receive multiple messages send by Python TCP client to a C# server.
I do receive the data, but all at once and I don't want that to happen.
I tried to set the server buffer size to the size of the byte[] which I am sending, but it didn't work (source).
Any ideas how can I fix this issue?
Client sending code:
import socket
def send_to_remote(sock, data):
data_bytes = bytearray()
data_bytes.extend(map(ord, data)) # appending the array with string converted to bytes
bytes_length = len(data_bytes) # length of the array that I am sending
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, bytes_length) # setting the buffer size to the array length
print(bytes_length)
sock.send(data_bytes) # sending the data
Server receiving code:
public static string ReadData(TcpClient connection)
{
StringBuilder receivedDataStr = new StringBuilder();
NetworkStream connectionStream = connection.GetStream();
if (connectionStream.CanRead)
{
byte[] connectionBuffer = new byte[connection.ReceiveBufferSize];
Console.WriteLine(">> Reading from NODE");
int bytesRead = 0;
bytesRead = connectionStream.Read(connectionBuffer, 0, 1024);
receivedDataStr.Append(Encoding.ASCII.GetString(connectionBuffer, 0, bytesRead));
Console.WriteLine(">> " + connection.ReceiveBufferSize);
return receivedDataStr.ToString();
}
else
{
Console.WriteLine(">> Can't read from network stream");
return "none-read";
}
}
EDIT:
What I do is:
send_to_remote(socekt, "msg1")
send_to_remote(socekt, "msg1")
And then:
string msg1 = ReadData(client);
string msg2 = ReadData(client);
I receive buffer array of 106200.
The result is:
"msg1 (then new line) msg2"
"" (string msg2 is waiting for data)
Thank you in advance!!
TCP is a stream protocol, not a packet protocol. There is absolutely no guarantee that you're going to get data in the same exact chunks that it was sent - all that is guaranteed is that you'll get the bytes in the correct order (or a failure, or a timeout, etc). You can get each byte separately, or 14 messages at once. Or anything in between, including half of a message in one receive, and the other half in the next. In the case of unicode (etc), this also means that a single character can be split over multiple receives.
Any multi-message protocol based on TCP needs to include some kind of framing, i.e. some way for you to know where each separate message starts and ends. Since you're using a text-based protocol, a common option is to separate logical messages with a CR, LF, or CR+LF - and then it is your job to buffer data until you have an entire message - by looking for the line ending. For completeness: in the case of binary protocols, it is common to length-prefix payloads with some kind of header that indicates the amount of data in the payload, then you just need to parse the header, determine the length, and buffer until you have that much data.
In simple applications with a text protocol and no challenging scalability concerns, it may be possible to use StreamReader (on top of a NetworkStream) to do that part for you, then just use ReadLine or ReadLineAsync. Note, however, that this would be a bad idea in "real" servers (especially ReadLine) - you don't want a malicious or just buggy client locking a thread forever just because it sent a few characters without the line ending, and then didn't send anything else ... ever. Of course, in a serious server you wouldn't be using a thread per client anyway.

issue with getting TcpClient server response as string

so long story short, i am trying to develop an application which requires having Tcp Connection to a server. having no previous experiance in this field i ended up with having none of my functions working. so i decided to make a simple console app just to check my commands and their responses. the part about setting up the connections went well, so does the part about wrting into network stream(i think) but i hit a wall when trying to display server respons:
each time my porgram reaches the line where it has to Encode server respons and WriteLine, my console application goes all black and all texts goes away. can you tell what's wrong with the code i am using?everything up until the part where console trys to display response goes well, i checked. i want to have server's respones as normal strings(if possible i guess...)
static void ServerTalk(TcpClient tcpClient,NetworkStream networkStream, StreamWriter streamWriter, StreamReader streamReader)
{
//Messaging methods:
Console.WriteLine("Client: ");
string message = Console.ReadLine();
streamWriter.WriteLine(message);
streamWriter.Flush();
//Response methode:
byte[] data = new byte[tcpClient.ReceiveBufferSize];
int ret = networkStream.Read(data, 0, data.Length);
string respond = Encoding.ASCII.GetString(data).TrimEnd();
Console.WriteLine("Server: ");
Console.WriteLine(respond);
ServerTalk(tcpClient, networkStream, streamWriter, streamReader);
}
you need to process only ret bytes, you are translating all bytes in the array.
copy to a new array that is 'ret' long and then decode.
var retarr = new byte[ret];
Array.Copy(data,retarr,ret);
string respond = Encoding.ASCII.GetString(retarr);
More importantly note that this method of tcp communication is not going to work. You are assuming that when you send x bytes in one block you will receive x bytes in one block, this is not so, you can send 1 100 byte message and receive 100 1 byte messages
This means that you task is much more complex. YOu need to devise a way of sending self describing data - so that you know its completely received. classically you send a length followed by the data. You then keep looping in the receive code till you have received that many bytes

TCPClient - stops receiving data after some time

I have wrote a code to listen data on particular port in TCP mode.
Now the problem here is that the below code receives some data from the remote and after sometime it does not receive anything
I have check the wireshark and data is coming over there
I have check the TCPView, port (2-3 entries of same port is there) is open with the application but few port status stays as "ESTABLISHED" and one port is saying "LISTENING"
If i am checking the wireshark for missign data detail, then i found that remote IP-Port pair is stated as "ESTABLISHED" in TCPView but it cannot write anything in log file
My question is why the no data received in my application. Is there anything wrong in the code? I have tried every option which google can provide but there is no luck.
TcpListener tcpListenerDeviceResponse = new TcpListener(new IPEndPoint(IPAddress.Parse(localIP), 6005));
tcpListenerDeviceResponse.Start();
while (true)
{
using (TcpClient client = tcpListenerDeviceResponse.AcceptTcpClient())
{
// Get a stream object for reading and writing
using (NetworkStream stream = client.GetStream())
{
Socket skSource = client.Client;
int i;
var data2 = new byte[client.ReceiveBufferSize];
// Loop to receive all the data sent by the client.
while ((i = stream.Read(data2, 0, data2.Length)) != 0)
{
// Translate data bytes to a ASCII string.
string strResponse = System.Text.Encoding.ASCII.GetString(data2, 0, i);
// Insert the data in log text file
// process data
}
stream.Close();
}
// Shutdown and end connection
client.Close();
}
}
tcpListenerDeviceResponse.Stop();
One Reason could be Timeout!
Assuming Transmitting socket doesn't send data for more than Receiving socket's timeout, it will result in Timeout Error and will break the while loop and Close the socket.
This MSDN link might help you!
Also, I would suggest you to close the socket only if it is breaking while for other reasons except Timeout. If Timeout occurs, Go on reading again.

Socket Client answer

I'm creating a client/server socket app. And I'm not being able to solve this problem, probably due to lack of knowledge on the matter.
The client must send an answer in order to proceed communication:
while(comunicate)
{
if (chkCorrectAnswer.Checked)
answer = encoder.GetBytes('\x02' + "82SP|" + '\x03');
else
answer = encoder.GetBytes("bla");
ServerStream.Write(answer, 0, answer.Length);
//or ??
//tcp.Client.Send(answer);
}
And the server recieves it:
while(comunicate)
{
var validanswer= encoder.GetBytes("myvalidanswer");
answer = new byte[validanswer.Length];
stream.Read(answer, 0, validanswer.Length);
//or ??
//tcp.Client.Receive(answer);
if (answer.SequenceEqual(validanswer))
// continue communication
}
Each code is in different app, looped "comunication thread".
The answer seems being sent correctly but the server doesn't seem to be recieveing it porperly. Sometimes it recieves blablab or lablabl and variations with 7 chars. I thoung the recieving would fill the buffer only with the incoming data and somehow it is filling the buffer with repeated data.
Two questions here:
What should I use, stream.write/read or client.send/recieve?
How to ensure this answer verification?
0x02 and 0x03 is called start of text (STX) and end of text (ETX) and are separators used to identify where your messages starts and ends. There is really no need to use both, it was a common practice when doing serial communication.
You need to continue building a message until ETX is received.
something like (easiest solution but not very efficient if you have lots of clients)
string buffer = "";
var readBuffer = new byte[1];
int readBytes = 0;
while ((readBytes = stream.Read(readBuffer, 0, 1)) == 1 && readBuffer[0] != 3)
{
buffer += readBuffer[0];
}
you can of course read larger chunks. But then you need to check if more than one message was arrived and process the buffer accordingly. That's how I would do it though.
I thoung the recieving would fill the buffer only with the incoming data and somehow it is filling the buffer with repeated data.
Well, you are repeatedly sending the data in a loop, so this is to be expected.
If you want to read only a certain number of bytes off the stream you need to also send the size of the logical packet ahead of it so that the receiving end can first read the size (say as a fixed int value) and then the actual response.
When you do the read you'll get everything you wrote including amything you've written previously.
Implement a length header or some kind of seperator so you know what's what --
length + message
or
message + seperator
Then parse it when you do the read.

C# void ReceiveData(IAsyncResult iar)

i would like some help with the following. this is to do with Asynchronous sockets.
from the sender:
string stringData = "Welcome to my server server server";
byte[] message1 = Encoding.ASCII.GetBytes(stringData);
//MessageBox.Show(message1.Length.ToString());
client.BeginSend(message1, 0, message1.Length, SocketFlags.None, new AsyncCallback(SendData), client);
here as can be seen, the message.length can be found.
--
on the client:
Socket remote = (Socket)iar.AsyncState;
int recv = remote.EndReceive(iar);
string stringData = Encoding.ASCII.GetString(data, 0, recv);
my question is is there a way to access the actual length of the sent data and based on that call recieve data until the complete message is recieved?
No - TCP/IP is a stream protocol. Just because you've sent the data with one call doesn't mean it will be sent as one packet, or that it won't be merged with other packets. In other words, sending "X" then "Y" is equivalent to sending "XY" - they may well be transmitted with the exact same packets, indistinguishable to the other end.
If you want the idea of an individual "message" in a stream, you should prefix the data with a few bytes explicitly stating its length. (An alternative is to use a delimiter, but I far prefer using a length prefix - it makes it easier to know how much data you've still got to receive, you don't need to worry about starting to consume the next message, and you don't have to worry about escaping the delimiter in some form.)
Only if something is transmitted to communicate the length - either pre-pend the length to the message, or send a terminator character of some kind.

Categories