c# sockets read data and then reply - c#

I am using the following code (built from answers to my previous questions on SO):
public void Start()
{
listener = new TcpListener(IPAddress.Any, 9030);
listener.Start();
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
}
private void HandleAsyncConnection(IAsyncResult res)
{
StartAccept();
TcpClient client = listener.EndAcceptTcpClient(res);
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
int readCount;
while ((readCount = ns.Read(data, 0, client.ReceiveBufferSize)) != 0)
{
sb.Append(Encoding.UTF8.GetString(data, 0, readCount));
}
// Do work
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
The line "Do work" represents where I will do the required processing for my client.
However I can't see how to use this code to read the client's data and then reply to it. When using this code I can read perfectly what is sent by my client, however once that occurs the client locks up and eventually complains that the connection was terminated. It does not receive my reply.
Any ideas on how to fix this?

Okay, first of all, you are mixing asynchronous calls (BeginAcceptTcpClient) and synchronous (Read and Write) calls. That completely kills the purpose of asynchronous code. Second, maybe this is why your socket gets closed ? Performing a sync op on an async socket. I'm not sure, but without the client code it's impossible to tell.
Anyway, this is NOT how you build an asynchronous, multi-client server.
Here is a fully asynchronous server implementation : http://msdn.microsoft.com/en-us/library/fx6588te.aspx

i think you should use a length byte to alloc your buffer. ReceiveBufferSize could be called multiple times, i think there is no gurantee you receive everything in one block.

You have misunderstood how Read works. It blocks until something is received from the other end point. The only time it returns 0 is when the other side have disconnected, hence you will continue reading until the other side disconnects.
When using TCP you need to know when a message ends. You can do that either by sending the message length first as a header or by using a suffix (as a line feed) after each message. Then you should keep reading until the complete message has arrived.

Related

Replicate PuTTY's raw connection with sockets

I am working with a heat cell with which i can only communicate through Ethernet. When trying to connect to it using sockets, I am stuck on waiting for the Receive() method to end.
I've checked the connection using PuTTY in raw mode and it worked just fine, I was able to send and receive messages.
This led me to believe that I needed to use some kind of raw communication as well, hence why I tried to use SharpPCap and the like. Using this, I am able to read from the cell (although I am faced with a few issues that aren't related to this post).
However, since I'm not very experienced with networking, I was wondering if there was a way to obtain the same results as when I used PuTTY's raw mode but using only Sockets ?
I've come accross this question that was left unanswered, apart from the fact that the author was advised not to use SocketType.Raw.
Below is the example from MSDN documentation that I adapted for my tests. It is supposed to send a request and then listen for the answer.
static void Main(string[] args)
{
System.Net.IPAddress host = System.Net.IPAddress.Parse("10.0.0.3");
int port = 2049;
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect(host, port);
if (socket.Connected)
{
string request = "99997¶1¶1\\r";
var byteSent = Encoding.Default.GetBytes(request);
var byteReceived = new byte[256];
socket.Send(byteSent, byteSent.Length, 0);
int bytes = 0;
do
{
bytes = socket.Receive(byteReceived, byteReceived.Length, 0); // this is the line I'm being stuck on
} while (bytes > 0);
Console.WriteLine($"Result : {Encoding.Default.GetString(byteReceived)}");
Console.ReadLine();
}
else
{
Console.WriteLine("Connection Failed");
Console.ReadLine();
}
}
UPDATE
I used WireShark to take a look at what was being sent from my application. Turns out the 'CR' and 'LF' werent sent correctly. But correcting this didn't solve my problem.
I can see the server's answer to my request on WireShark, but still I can't read anything using socket.Receive(). Could it be possible that the server is faster to answer than my machine is to start listening ? I tried setting up the socket.ReceiveTimeout property and put my send/receive instructions in a loop, but still nothing returning from the Receive() statement.
The socket is in blocking mode by default (cf Socket.Blocking). That mean that, for your case, blocking until 256 byte has been read (Without timeout by default Socket.ReceiveTimeout).
You may want to set the Blocking mode to false, or set a Receive timeout in order to not block indefinitly.
Alternatively, you may want also to use async method to avoid blocking the main thread.

TcpListener: Detecting a client disconnect as opposed to a client not sending any data for a while

I was looking how to detect a 'client disconnect' when using a TcpListener.
All the answers seem to be similar to this one:
TcpListener: How can I detect a client disconnect?
Basically, read from the stream and if Read() returns 0 the client had disconnected.
But that's assuming that a client disconnects after every single stream of data it sent.
We operate in environments where the TCP connect/disconnect overhead is both slow and expensive.
We establish a connection and then we send a number of requests.
Pseudocode:
client.Connect();
client.GetStatus();
client.DoSomething();
client.DoSomethingElse();
client.AndSoOn();
client.Disconnect();
Each call between Connect and Disconnect() sends a stream of data to the server.
The server knows how to analyze and process the streams.
If let the TcpListener read in a loop without ever disconnecting it reads and handles all the messages, but after the client disconnects, the server has no way of knowing that and
it will never release the client and accept new ones.
var read = client.GetStream().Read(buffer, 0, buffer.Length);
if (read > 0)
{
//Process
}
If I let the TcpListener drop the client when read == 0 it only accepts
the first stream of data only to drop the client immediately after.
Of course this means new clients can connect.
There is no artificial delay between the calls,
but in terms of computer time the time between two calls is 'huge' of course,
so there will always be a time when read == 0 even though that does not mean
the client has or should be disconnected.
var read = client.GetStream().Read(buffer, 0, buffer.Length);
if (read > 0)
{
//Process
}
else
{
break; //Always executed as soon as the first stream of data has been received
}
So I'm wondering... is there a better way to detect if the client has disconnected?
You could get the underlying socket using the NetworkStream.Socket property and use it's Receive method for reading.
Unlike NetworkStream.Read, the linked overload of Socket.Receive will block until the specified number of bytes have been read, and will only return zero if the remote host shuts down the TCP connection.
UPDATE: #jrh's comment is correct that NetworkStream.Socket is a protected property and cannot be accessed in this context. In order to get the client Socket, you could use the TcpListener.AcceptSocket method which returns the Socket object corresponding to the newly established connection.
Eren's answer solved the problem for me. In case anybody else is facing the same issue
here's some 'sample' code using the Socket.Receive method:
private void AcceptClientAndProcess()
{
try
{
client = server.Accept();
client.ReceiveTimeout = 20000;
}
catch
{
return;
}
while (true)
{
byte[] buffer = new byte[client.ReceiveBufferSize];
int read = 0;
try
{
read = client.Receive(buffer);
}
catch
{
break;
}
if (read > 0)
{
//Handle data
}
else
{
break;
}
}
if (client != null)
client.Close(5000);
}
You call AcceptClientAndProcess() in a loop somewhere.
The following line:
read = client.Receive(buffer);
will block until either
Data is received, (read > 0) in which case you can handle it
The connection has been closed properly (read = 0)
The connection has been closed abruptly (An exception is thrown)
Either of the last two situations indicate the client is no longer connected.
The try catch around the Socket.Accept() method is also required
as it may fail if the client connection is closed abruptly during the connect phase.
Note that did specify a 20 second timeout for the read operation.
The documentation for NetworkStream.Read does not reflect this, but in my experience, 'NetworkStream.Read' blocks if the port is still open and no data is available, but returns 0 if the port has been closed.
I ran into this problem from the other side, in that NetworkStream.Read does not immediately return 0 if no data is currently available. You have to use NetworkStream.DataAvailable to find out if NetworkStream.Read can read data right now.

Windows phone 7 TCP network client

Basically, I've written a windows phone 7 client, which is supposed to receive a very long string from the server. However, there seem to be some limitations on the phone networking code, and am having trouble figuring out how to do this. The following is the code I am using:
public string Receive()
{
string response = "Operation Timeout";
StringBuilder content = new StringBuilder();
// We are receiving over an established socket connection
if (_socket != null)
{
// Create SocketAsyncEventArgs context object
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
// Setup the buffer to receive the data
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
// Inline event handler for the Completed event.
// Note: This even handler was implemented inline in order to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Receive request over the socket
_socket.ReceiveAsync(socketEventArg);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
As it stands, this will only accept the first N bytes of the message and return that... any help on how to do this would be greatly appreciated! Thanks!
Firstly, I would try to redesign your code to be appropriately async - working round the fact that WP7 doesn't offer synchronous IO by building your own isn't nearly as clean as embracing the asynchrony.
Secondly, you're assuming that you only need a single ReceiveAsync call to get the whole data. Assuming your using TCP, that's a stream-based protocol. You'll need to either add some sort of delimiter or length prefix, or keep reading until the other side closes the connection if that's the way your protocol works.
(Any reason you're not doing this with HTTP and WebClient or WebRequest, by the way?)
Firstly, I would try to redesign your code to be appropriately async - working round the fact that WP7 doesn't offer synchronous IO by building your own isn't nearly as clean as embracing the asynchrony.
Secondly, you're assuming that you only need a single ReceiveAsync call to get the whole data. Assuming your using TCP, that's a stream-based protocol. You'll need to either add some sort of delimiter or length prefix, or keep reading until the other side closes the connection if that's the way your protocol works.
(Any reason you're not doing this with HTTP and WebClient or WebRequest, by the way?)

TCP listener cuts message at 1024 bytes

Problem just started on client side. Here is my code where I receive TCP/IP message. On my local PC this listener receives many K no problem. I tried to increase buffer size but on client site they still report issues related to it.. Still get's only first 1K (1024 bytes)
public void Start()
{
//Define TCP listener
tcpListener = new TcpListener(IPAddress.Any, IDLocal.LocalSession.PortNumber);
try
{
//Starting TCP listenere
tcpListener.Start();
while (true)
{
var clientSocket = tcpListener.AcceptSocket();
if (clientSocket.Connected)
{
var netStream = new NetworkStream(clientSocket);
// Check to see if this NetworkStream is readable.
if (netStream.CanRead)
{
var myReadBuffer = new byte[1024];
var myCompleteMessage = new StringBuilder();
// Incoming message may be larger than the buffer size.
do
{
var numberOfBytesRead = netStream.Read(myReadBuffer, 0, myReadBuffer.Length);
myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
} while (netStream.DataAvailable);
//All we do is response with "OK" message
var sendBytes = Encoding.ASCII.GetBytes("OK");
netStream.Write(sendBytes, 0, sendBytes.Length);
clientSocket.Close();
netStream.Dispose();
// Raise event with message we received
DataReceived(myCompleteMessage.ToString());
}
}
}
}
catch (Exception e)
{
//If we catch network related exception - send event up
IDListenerException(e.Message);
}
}
I don't see any problem with the code you posted to extract the message into a string, so I 'm guessing that something else is afoot.
TCP isn't required to send all data you queue to it in one go. This means it can send as few as it want to at a time, and it can choose to split your data into pieces at will. In particular, it is guaranteed to split your data if they don't fit into one packet. Typically, the maximum packet size (aka MTU) is 1532 bytes IIRC.
Therefore there's a real possibility that the data is sent, but as more than one packet. The delay between reception of the first and second packet could mean that when the first one arrives your code happily reads everything it contains and then stops (no more data) before the second packet has had time to arrive.
You can test this hypothesis by either observing network traffic, or allowing your app to pull more messages from the wire and see if it finally does get all the data you sent (albeit in pieces).
Ultimately the underlying issue is TCP's fundamental stream-based (and not message-based) nature; even if you get this code to work correctly, there is no guarantee that it will continue working in the future because it makes assumptions about stuff that TCP does not guarantee.
To be safe, you will need to incorporate a message-based structure (e.g. prepending each piece of data with exactly 4 bytes that hold its length; then, you can just keep reading forever until you have received that many bytes).

tcpclient listening implementation

I am trying to implement a tcp client listening function. This means that after connection established with server, this tcp client just sit there and waiting for new data to arrive.
Here is my code but when it runs, it complain about not been able to read anything from the
network stream. But the server hasn't started sending data yet. I guess the complains is because
of the timeout in tcp client.
Is this the right way to do it?
public void listen(dataHandler processDataFuc)
{
NetworkStream stream;
Byte[] data_buffer = new Byte[MAX_PACKET_SIZE];
if(!this.Connected)
{
this.Connect();
}
while (!this.terminate_listening)
{
stream = main_client.GetStream();
while (stream.Read(data_buffer, 0, data_buffer.Length) > 0)
{
processDataFuc(data_buffer);
}
}
}
Thanks
The short answer is yes, it'll do what you want, but it's not ideal. I'd first suggest moving stream = main_client.GetStream(); out of the while loop, as you're just getting the same stream over and over. Also, using NetworkStream.Read isn't the best way to perform a continuous read if you're expecting intermittent data over a long period of time, as it's holding up a thread just for that one task; better to use BeginRead and pass in a callback, which will return immediately but later alert you when data is available (via the callback).
Checkout the methods EstablishConnection() and IncomingDataSyncWorker() (synchronous) or IncomingPacketHandler() (asynchronous) for examples of what you want to do. All these methods are part of networkComms.net an opensource network communication library.
What version of .Net are you using?
If you are using .Net 4.0 or 4.5, then you can use ReadAsync() instead of Read().
Consider this:
public async void listen(dataHandler processDataFuc)
{
NetworkStream stream;
Byte[] data_buffer = new Byte[MAX_PACKET_SIZE];
if(!this.Connected)
this.Connect();
stream = main_client.GetStream();
while (!this.terminate_listening)
{
await stream.ReadAsync(data_buffer, 0, data_buffer.Length)
processDataFuc(data_buffer);
}
}
In such way, ReadAsync() will waits in a separate Thread until server sends some Data. Then the rest of your code will execute.

Categories

Resources