How do I reply asynchronously to a client using sockets in C#? - c#

I have basically implemented this asynchronous server socket example (and the corresponding client). Using it, I can respond to the client if I follow the example exactly, i.e., if the call to Send() the response is in the ReadCallback() method.
If, however, I try and send a response outside of here, i.e., in a callback that I've attached to my message processing routine (running in a different thread), I get this error, saying the Socket is not connected. If I try and send a response somewhere else in the Server code, say in the while(true) loop that's listening to incoming connections, I get the same error.
Am I missing something fundamental here?
Edit:
Ok, so I read Two-way communication in socket programming using C, and I now think, according to that answer, that I have to modify the example I linked to so that I reply to the server on the socket returned by the accept process. My goal is to be able to call Send() outside of the receive callback, say from Main(), after the client and server are connected.
Please can someone suggest how I modify the example to achieve what I want? I'm getting thoroughly confused about this, and don't want to create a separate stream if I don't need to (which according to the question I posted, I don't need to...).

If you want to keep the connection open then would need to persist the handler variable as that is the open socket connection. Then whenever you want to send that connection a message you retrieve its socket and send.
Also, you obviously wouldn't call Shutdown() and Close() on the handler variable.

Related

Check if NamedPipeClientStream write is successful

Basically the title... I'd like to have same feedback on weather NamedPipeServerStream object successfully received a value. This is the starting code:
static void Main(string[] args){
Console.WriteLine("Client running!");
NamedPipeClientStream npc = new NamedPipeClientStream("somename");
npc.Connect();
// npc.WriteTimeout = 1000; does not work, says it is not supported for this stream
byte[] message = Encoding.UTF8.GetBytes("Message");
npc.Write(message);
int response = npc.ReadByte();
Console.WriteLine("response; "+response);
}
I've implemented a small echo message from the NamedPipeServerStream on every read. I imagine I could add some async timeout to check if npc.ReadByte(); did return a value in lets say 200ms. Similar to how TCP packets are ACKed.
Is there a better way of inspecting if namedPipeClientStream.Write() was successful?
I'd like to have same feedback on weather NamedPipeServerStream object successfully received a value
The only way to know for sure that the data you sent was received and successfully processed by the client at the remote endpoint, is for your own application protocol to include such acknowledgements.
As a general rule, you can assume that if your send operations are completing successfully, the connection remains viable and the remote endpoint is getting the data. If something happens to the connection, you'll eventually get an error while sending data.
However, this assumption only goes so far. Network I/O is buffered, usually at several levels. Any of your send operations almost certainly involve doing nothing more than placing the data in a local buffer for the network layer. The method call for the operation will return as soon as the data has been buffered, without regard for whether the remote endpoint has received it (and in fact, almost never will have by the time your call returns).
So if and when such a call throws an exception or otherwise reports an error, it's entirely possible that some of the previously sent data has also been lost in transit.
How best to address this possibility depends on what you're trying to do. But in general, you should not worry about it at all. It will typically not matter if a specific transmission has been received. As long as you can continue transmitting without error, the connection is fine, and asking for acknowledgement is just unnecessary overhead.
If you want to handle the case where an error occurs, invalidating the connection, forcing you to retry, and you want to make the broader operation resumable (e.g. you're streaming some data to the remote endpoint and want to ensure all of the data has been received, without having to resend data that has already been received), then you should build into your application protocol the ability to resume, where on reconnecting the remote endpoint reports the number of bytes it's received so far, or the most recent message ID, or whatever it is your application protocol would need to understand where it needs to start sending again.
See also this very closely-related question (arguably maybe even an actual duplicate…though it doesn't mention named pipes specifically, pretty much all network I/O will involve similar issues):
Does TcpClient write method guarantees the data are delivered to server?
There's a good answer there, as well as links to even more useful Q&A in that answer.

Multiple client with async TCP listener in C#

I have a problem with async TCP listener in C#. The main problem is I want to create async TCP listener in order to handle multiple connections. I have tons of requests from devices and webpages. Also I have to use database to write specific information from these connections (read/write to/from SQL Server).
The scenario of our task is this: One REST request will post from a webpage with a unique identifier to our Web API. Then our Web API makes a TCP connection to our listener, so we must halt this connection until we get another connection from a device with that unique identifier. Then we send data which we got it before (webpage connection) to this connected device and again we must halt this connection too. After processing this data in the device it will send us some other data again, and we must send this data to webpage which we halted it before.
How can I find halted connection in our listener?
Is there a better solution for us? (except using async TCP listener)
Because of some customer reasons we are unable to use signalR or self-hosted Web API in C#.
Regards,
Sara
'Halt' isn't the best word to describe what you need. If you need two-way communication with a web page over a REST request, you simply need to keep that request pending until the response is ready (not recommended, it could take really long and the connection could be dropped due to network conditions). Do reconsider your choice of avoiding SignalR. However, if need be, you can keep the request thread waiting. To do that, you'd need either a TaskCompletionSource (if you're processing the request within a Task) or a synchronization primitive such as a ManualResetEvent. I can't really give you more details without knowing the conditions your code will run under.
On the device side of things, again you need two way communication. You could implement this in one of two ways:
The device opens a TCP connection and keeps it open. The server receives the ID, and then sends the data back over the connection. The device then processes this data in some way and sends its response back to the server over the same connection and terminates the connection.
The device makes the equivalent of a REST GET request to the server to grab the data from the web page. It then processes the data and makes the equivalent of a POST request to send its own data back to the server.
After this is done, you still have the connection from the web page waiting for a response. Simply let it know the transaction has completed, using TaskCompletionSource.SetResult or ManualResetEvent.Signal. The server can then write whatever data it needs in the response to the web page's request and close that connection too.
Also note that there is no such thing as a halted connection. You just intentionally delay writing a response.
EDIT: You can't really hold the connection (not with the normal execution flow of most web servers at least), but you can stop the thread processing that connection. This is a heavily simplified (and completely inappropriate for any real system) example:
// ConnectionManager.cs
public static Dictionary<Guid, TaskCompletionSource<DataToSendToWebPage>> connectionTCSs;
// WebPageRequestHandler.cs
async Task HandleClientRequest() {
// do some stuff
var tcs = new TaskCompletionSource<DataToSendToWebPage>();
ConnectionManager.connectionTCSs[deviceID] = tcs;
var result = await tcs.Task; // This is where you wait for the other flow to complete
// Write response to connection
}
// DeviceRequestHandler.cs
void HandleRequest() {
// do stuff
ConnectionManager.connectionTCSs[clientID].SetResult(result);
}
The general idea is that you keep the thread (or task) processing the web page request waiting, and then signal it to continue from the other thread when the device's connection is handled and data is received.

TcpClient: How do I close and reconnect it again?

Hello and thanks for your help.
This time I would like to ask about TcpClient.
I have a server program and I am writing a client program.
This client uses TcpClient. It starts by creating a new client
clientSocket=new TcpClient();
(By the way, can this cause exceptions? just in case I put it inside a try-catch but I am not sure if that is really necessary)
Anyway, later I enter a loop and inside this loop I connect to the server
clientSocket.Connect("xx.xx.xx.xx",port);
Then I create a NetworkStream with
clientStream=clientSocket.GetStream();
and then start waiting for data from the server through Read. I know this is blocking so I also set a ReadTimeOut (say 1 second)
Anyway, so far so good.
Later if I don't receive anything from the server, I attempt to send something to it. If this keeps happening for say 3 times I want to close the connection and reconnect to the server again
(notice that a whole different problem is when the server somehow is down, cause that causes other kinds of errors in the client-perhaps I will ask about that later)
So, what do I do?
if(clientSocket.Connected)
{
Console.WriteLine("Closing the socket");
clientSocket.Close();
}
I close the socket.
The loop is finished so I go again to the beginning and try to connect to the server.
clientSocket.Connect("xx.xx.xx.xx",port);
However this causes an error(an unhandled exception actually) "Can not access a disposed object"
So my question is How can I close and reconnect to the server again??
Thanks again for any help
A TcpClient instance can only be used to connect once. You can simply instantiate a new TcpClient, rather than trying to re-open a closed one.
As explained in the other answer, a TcpClient object can only be connected once. If you want to reconnect to the server, you have to create a new TcpClient object and call Connect() again.
That said, you have a number of apparent misconceptions in your question:
First and most important, you should not use ReceiveTimeout if you have any intention whatsoever of trying to use the TcpClient object again, e.g. to send some data to the server. Once the timeout period has expired, the underlying socket is no longer usable.If you want to periodically send data to the server when the server hasn't sent data to you, you should use asynchronous I/O (which you should do anyway, in spite of the learning curve) and use a regular timer object to keep track of how long it's been since you received data from the server.
The TcpClient constructor certainly can throw an exception. At the very least, any attempt to new a reference type object could throw OutOfMemoryException, and in the case of TcpClient, it ultimately tries to create a native socket handle, which could also fail.While all I/O objects and methods can throw exceptions, you should only ever catch exceptions that you have a way to handle gracefully. So before you add a try/catch block to your code, decide what it is you want to do in the case of an exception that will ensure that your code doesn't corrupt any data and continues to operate correctly. It is generally not possible to gracefully handle OutOfMemoryException (and impractical to protect all uses of new in any case), but you certainly can catch SocketException, which could be thrown by the constructor. If that exception is thrown, you should immediately abandon the attempt to create and use TcpClient, and report the error the user so that they can attempt to correct whatever problem prevented the socket's creation.
If your server is expected to be sending you data, and you don't receive it, then closing the connection and retrying is unlikely to improve the situation. That will only cause additional load on the server, making it even more likely it will fail to respond. Likewise sending the same data over and over. You should your request once, wait as long as is practical for a response from the server, and if you get no response within the desired time, report the error to the user and let them decide what to do next.Note that in this case, you could use the ReceiveTimeout property, because all you're going to do if you don't get a response in time is abandon the connection, which is fine.
Very simple:
client.Close();
client = new TcpClient();
client.Connect(host, port);

Identify the socket with multiple async tcp clients

My application has many tcpclients that is uses to update hundreds of servers when instructed. I'm having trouble in the design with a minor but important issue.
My programs takes an outgoing message out of a queue and selects an available client from an array of clients, I'll call this client1. It starts a connection on the tcpclient with a BeginConnect and issues a call back method. The program then moves on to other messages from the queue and the tcpclients that will be sending them.
When the the callback happens for client1, my program gets an AsyncResult from which I can resolve the socket.
Here is my problem. How do I know which socket or TCPClient I have? It's important because I need to know which message to send on this connected client.
I've looked on the socket and didn't find a name property.
How do I identify the socket so I know the correct messaging conversation to have?
Thanks!
After more study and research I realized the callback would pass any System.Object. So the answer is as simple as wrapping the TCPClient in a class that has properties that can identify it's purpose.
In my case a simple class with a Socket, String for the message, string for the IP, and an int for the Port was enough to handle the situate when it made it to the call back. Just remember you have to cast the IAsyncResult.AsyncState back to the type of your wrapper class.

TcpClient.BeginRead/TcpClient.EndRead doesn't throw exception when internet disconnected

I'm using TcpListener to accept & read from TcpClient.
The problem is that when reading from a TcpClient, TcpClient.BeginRead / TcpClient.EndRead doesn't throw exception when the internet is disconnected. It throws exception only if client's process is ended or connection is closed by server or client.
The system generally has no chance to know that connection is broken. The only reliable way to know this is to attempt to send something. When you do this, the packet is sent, then lost or bounced and your system knows that connection is no longer available, and reports the problem back to you by error code or exception (depending on environment). Reading is usually not enough cause reading only checks the state of input buffer, and doesn't send the packet to the remote side.
As far as I know, low level sockets doesn't notify you in such cases. You should provide your own time out implementation or ping the server periodically.
If you want to know about when the network status changes you can subscribe to the System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged event. This is not specific to the internet, just the local network.
EDIT
Sorry, I misunderstood. The concept of "connected" really doesn't exist the more you think about it. This post does a great job of going into more details about that. There is a Connected property on the TcpClient but MSDN says (emphasis mine):
Because the Connected property only
reflects the state of the connection
as of the most recent operation, you
should attempt to send or receive a
message to determine the current
state. After the message send fails,
this property no longer returns true.
Note that this behavior is by design.
You cannot reliably test the state of
the connection because, in the time
between the test and a send/receive,
the connection could have been lost.
Your code should assume the socket is
connected, and gracefully handle
failed transmissions.
Basically the only way to check for a client connection it to try to send data. If it goes through, you're connected. If it fails, you're not.
I don't think you'd want BeginRead and EndRead throwing exceptions as these should be use in multi threaded scenarios.
You probably need to implement some other mechanism to respond to the dropping of a connection.

Categories