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.
Related
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.
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);
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
I have a TCP client that successfully connects to an external Server and I am sending a request to the server which is received successfully.
However when I try and receive the response it just stalls and never receives it.
var message = "Hello World!";
var port = 9999; //Changed for question
var ip = "100.100.100.100"; //Changed for question
var tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
await tcpclnt.ConnectAsync(ip, port);
Console.WriteLine("Connected");
Stream stm = tcpclnt.GetStream();
byte[] ba = Encoding.ASCII.GetBytes(message);
Console.WriteLine("Transmitting {0}", message);
await stm.WriteAsync(ba, 0, ba.Length);
byte[] bb = new byte[100];
var bytesRecieved = await stm.ReadAsync(bb, 0, 100);
var response = new StringBuilder();
foreach (byte t in bb)
response.Append(Convert.ToChar(t));
Console.WriteLine("Received {0}", response);
tcpclnt.Close();
I have the correct port open on my computer and on my router.
There's many things wrong with your code, but one of the biggies is that the other side has no way of knowing when you're done transmitting.
TCP is a stream-based protocol, not a message-based one. That means that there's no 1:1 mapping between sends on one side, and reads on the other. It's like writing and reading a file stream, not like sending e-mail.
This among other things means that unless you're actually working with streamed data, you'll need some way to distinguish messages in the stream from each other. For example, by adding \r\n to each of your strings - but that's something the client and the server have to agree on. You'll have to also show the server code if you want more specific help.
As for the other mistakes:
You can't igore the return value of ReadAsync - it tells you how much data was actually read.
You can't just wave-away the encoding issues - both sides have to explicitly use an (agreed upon) encoding for writing and reading. In your case, this would mean using Encoding.ASCII.GetString instead of Convert.ToChar.
Related to the first point, you can't just call ReadAsync once and expect to get the whole message (or even expect to get exactly one message). For anything realistic, you'll need a loop, reading data as long as there is some.
No handling of graceful shutdown. Not important if you're only doing HTTP-style "request -> response", but problematic otherwise.
Im not sure whether this topic have been disscussed or not, but i have no idea what to do. In c#, i need to send message to other people in my networks. I made some researches, and all pointing to socket methods. With this method, logically it will work like this:
open up socket
Encode the message(to ascii for example)
Put the encoded bytes in an array
Send over the array
On the other side there's also a socket opened, and then it's the same thing in reverse order.
So i found this code, Can anyone help me understanding the code, which are similar on what i want:
IPEndPoint ip = new IPEndPoint(IPAddress.Any,9999);
//no.1
Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ip);
socket.Listen(10);
Console.WriteLine("Waiting for a client...");
Socket client = socket.Accept();
IPEndPoint clientep =(IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("Connected with {0} at port {1}",clientep.Address, clientep.Port);
//no.2 & 3
string welcome = "Welcome";
byte[] data = new byte[1024];
data = Encoding.ASCII.GetBytes(welcome);
//no.4
client.Send(data, data.Length,SocketFlags.None);
while(true)
{
data = new byte[1024];
int receivedDataLength = client.Receive(data);
Console.WriteLine(Encoding.ASCII.GetString(data, 0, receivedDataLength));
client.Send(data, receivedDataLength, SocketFlags.None);
}
Console.WriteLine("Disconnected from {0}",clientep.Address);
client.Close();
socket.Close();
I manage to understand what the code do until point no 4. but this code:
while(true)
{
data = new byte[1024];
int receivedDataLength = client.Receive(data);
Console.WriteLine(Encoding.ASCII.GetString(data, 0, receivedDataLength));
client.Send(data, receivedDataLength, SocketFlags.None);
}
I'm not sure what the above codes do?
and for the point no 5, can someone explain in to me how to do that? is that mean, that i need another program as a receiver?
~Thank you~
The code you're looking at is for an echo server, which reads some data sent to a socket by another client, prints it to the console, and then sends it back to the client that it came from. This is what the code in point 5 does. Here's what is going on:
data = new byte[1024];
this is just allocating a buffer to hold the data that we're going to read.
int receivedDataLength = client.Receive(data);
this receives data from the socket. Receive is a blocking call, so it won't return until there is data to be read OR until the socket is disconnected or has an error, at which point it throws. The recievedDataLength variable is EXTREMELY important because this tells us how many bytes we actually read. The number of bytes read may easily be LESS than the size of the buffer, because we don't know how many bytes were sent to the socket by the other client. By detecting how many bytes were read, we can be sure that we know how much data is actually in our buffer. If this returns 0, it means that the connection was closed by the other side.
Console.WriteLine(Encoding.ASCII.GetString(data, 0, receivedDataLength));
This just converts the buffer from arbitrary byte values to an ASCII string. Note that receivedDataLength allows us to only write out a string for the number of bytes that were read from the socket. If we just wrote the contents of the entire buffer, you'd get random crap on the console since any data present in the buffer that occurs AFTER receivedDataLenth is unknown.
client.Send(data, receivedDataLength, SocketFlags.None);
Finally, we're sending the data back to the other end of the connection by writing it to the socket. We use receivedDatalength to indicate that we only want to send the bytes that we actually read instead of the whole buffer. If you were sending a different message here, you'd want to use the length in bytes of the message that you're sending. You'll most likely never need to set any SocketFlags so don't worry about these.
Now this code here is for a server that wants to receive connections. To make a connection, the code is very similar, except after you call Socket.Bind(ip) you'll call Socket.Connect(remotehost) instead of Listen() and Accept(). Then the code to write data to the Socket is the same as in step 5 above.
One last thing: the Socket.Accept() method is non-intuitive at first so I'll explain what it's doing. Calling Listen() tells the socket to allow incoming connections, but in order to actually use those connections for something, you have to accept them. Accept() blocks until a new connection is made, then it returns a NEW socket object. This socket is similar to the socket that you're listening on, except that this socket represents a socket-pair, meaning that on the other end of the connection there is another similar socket that is going to talk to this one. You should use this new socket to talk to the client that has connected.
Once you've gotten the new Socket from Accept(), you still have the old socket, which is the one you originally called Accept() on. This socket is still listening for new connections, so if you want to allow more machines to connect to this socket, you need to keep calling Accept() until you are no longer willing to accept connections (like if you don't want there to be more than some arbitrary number of connections) or until you want to shut down the application. Now I said before that Accept() is a blocking call, so if you call it again it will not allow the thread you're on to do anything else until a new connection comes in. This means that you need to do one of two things: Either call BeginAccept to accept new clients asynchronously, OR use BeginRead or BeginSend to handle your socket I/O asynchronously. You CANNOT do both of these things on the same thread. It's a bit harder to do this, but check out the IPv6Sockets sample on MSDN (http://msdn.microsoft.com/en-us/library/8sd71sfs(VS.80).aspx) and you can see how this is done. Remember, it is absolutely necessary that you do NOT try to accept new connections and perform I/O on existing connections on the same thread. I actually recommend that you do everything with your sockets asynchronously.
If you don't want to have to use all this socket stuff, you can also check out the TcpClient class. It's a thin wrapper around Socket that allows you to grab a Stream object from the TcpClient and just read/write from that stream. It's way easier to use but it's not as powerful as a Socket, although for your application I doubt you'll need to use anything fancy with Sockets anyway so TcpClient is what I would use.
It looks like it's sitting in a loop receiving data and writing it to the console, and echoing back to the sender.