I was trying to find any good and clear example of asynchronous NamedPipeServerStream and couldn't find any suitable for me.
I want to have NamedPipe Server which is asynchronously accept messages from clients. The client is simple and it's fine for me. But I can't find examples of server, or can't understand how it works.
Now as I understand I need to create NamedPipeServerStream object. Let's do this:
namedPipeServerStream = new NamedPipeServerStream(PIPENAME, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, BUFFERSIZE, BUFFERSIZE);
Seems to work. But I don't know, do I have to use PipeSecurity or PipeAccessRule at all? Do I? My server will work as a windows service in a local system.
What next? I'm thinking I need to use BeginWaitForConnection for async connections. Let's see:
namedPipeServerStream.BeginWaitForConnection(WaitForConnectionAsyncCallback, <some strange thing>);
Question 1: What is this "some strange thing"? How to use it?
Question 2: Should I do
while(true)
{
namedPipeServerStream.BeginWaitForConnection(WaitForConnectionAsyncCallback, <some strange thing>);
}
To make my server always wait for connections? Or I need to do it somehow else?
And then... Let's take a look into WaitForConnectionAsyncCallback function:
private void WaitForConnectionAsyncCallback(IAsyncResult result)
{
Console.WriteLine("Client connected.");
byte[] buff = new byte[BUFFERSIZE];
namedPipeServerStream.Read(buff, 0, namedPipeServerStream.InBufferSize);
string recStr = General.Iso88591Encoding.GetString(buff, 0, namedPipeServerStream.InBufferSize);
Console.WriteLine(" " + recStr);
namedPipeServerStream.EndWaitForConnection(result);
}
..This doesn't work of course. Because I don't know how exactly to receive string from stream. How? Now it raises an InvalidOperationException:
Pipe hasn't been connected yet.
So how to organize asynchronous work with NamedPipeServerStream?
You tinker with the PipeSecurity to restrict access to the pipe, allowing only blessed programs to connect to your service. Put that on the back-burner until you've got this working and have performed a security analysis that shows that this kind of restriction is warranted.
The "some strange thing" is simply an arbitrary object that you can pass to the callback method. You don't often need it but it can be helpful if you write your callback so it serves multiple connections. In which case you need to know more about the specific pipe that got connected, the state argument allows you to pass that info. In your callback method, the result.AsyncState property gives you the reference back to that object. Only worry about that later, you'll find a use for it when you need it. Just pass null until then.
That's a bug. You must call EndWaitForConnection() first, before doing anything else with the pipe. Simply move it to the top of the method. You typically want to write it inside a try/catch so you can catch ObjectDisposedException, the exception that will be raised when you close the pipe before exiting your program.
Related
I have a network equipment to which I connect once using sockets, and the connection is maintained open all the time until application closes.
Now I have a class in C# that encapsulates the communication. There is a method SendMessage to the equipment. I need to use Socket.ReceiveAsync to get the response.
Let's say there are 3 methods: 1. GetEqValA(), GetEqValB(), GetEqValC() that call SendMessage with a specific message for the equipment.
I have created only one instance of socket Event args like that:
_completeArgs = new SocketAsyncEventArgs();
_completeArgs.SetBuffer(buffer, 0, buffer.Length);
_completeArgs.UserToken = _mySocket;
_completeArgs.RemoteEndPoint = _mySocket.RemoteEndPoint;
_completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(DataAvailable);
_mySocket.ReceiveAsync(_completeArgs);
Now, the DataAvailable method has something similar to the code below:
for (int i = 0; i < e.BytesTransferred; i++)
{
_tcpData.Add(e.Buffer[i]);
}
if (_tcpData.Count == _expectedTcpDataCount)
{
_expectedTcpDataCount = -1;
ProcessData();
// I don't want to put here, because it will wait for data until
// someone sends a message and the equipment responds with data
//_mySocket.ReceiveAsync(e);
}
else
{
_mySocket.ReceiveAsync(e);
}
Now, the 3 methods from above can be called by anyone, even different threads. I do have a lock mechanism for that.
My problem is that if I reuse _completeArgs in SendMessage for the next message to send, I get an exception that this eventArgs object is already in use by an asynchronous operation, whereas if I do the same(but not directly, by taking the SocketAsyncEventArgs e parameter from DataAvailable) in DataAvailable, no problem occurs.
_mySocket.ReceiveAsync(_completeArgs);
_mySocket.Send(pMessage);
The idea is that I don't want to call ReceiveAsync all the time, even if I know that nothing will come in there, but I want to call ReceiveAsync before sending any message to the device, because I know that I will get something.
The exception appears at method GetEqValC(), if I call them one after another in the sequence A,B,C.
What I don't understand, can you help me? Can I don what I want to do?
I use .NET 3.5.
P.S. Summary: I need to keep the connection alive, but read something from it only when I know for sure I must have something in there. Only one call at a time will be. One send, followed by one receive!
I was trying to develop a multicast receiver program and socket initialization was done as shown below:
public void initializeThread()
{
statuscheckthread = new Thread(SetSocketOptions);
statuscheckthread.IsBackground = true;
}
private void Form1_Load(object sender, EventArgs e)
{
rxsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
iep = new IPEndPoint(IPAddress.Any, 9191);
rxsock.Bind(iep);
ep = (EndPoint)iep;
initializeThread();
statuscheckthread.Start();
}
public void SetSocketOptions()
{
initializeThread(); //re-initializes thread thus making it not alive
while (true)
{
if (NetworkInterface.GetIsNetworkAvailable())
{
bool sockOptnSet = false;
while (!sockOptnSet)
{
try
{
rxsock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("224.50.50.50")));
rxsock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 64);
sockOptnSet = true;
}
catch
{
//Catch exception here
}
}
}
break; // Break out from loop once socket options are set
}
}
When my PC is not connected to a network, SetSocketOption method was throwing exception and even after network is connected,
I was unable to receive data because socket options are not set.
To avoid this I used a thread which runs in the background checking
for network availability and once network is available, it sets the socket options.
It works properly in some PC's but in some others, NetworkInterface.GetIsNetworkAvailable()
returned true before network got connected
(while network was being identified) .
So, to make sure Socket options are set, I used a bool variable sockOptnSet
which is set as
true if all the statements in the try block is executed as shown inside the method public void SetSocketOptions()
This program works fine in all PC's I tried, but I am doubtful about how much I can rely on this to work.
My questions are:
1) Is this good practice?
2) If not, what are the possible errors or problems it may cause? And how can I implement it in a better way?
Is this a good practice?
No, not a good practice. The vast majority of exceptions, including your first one, fall in the category of vexing exceptions. Software is supposed to work, worked well when you tested it, but doesn't on the user's machine. Something went wrong but you do not know what and there isn't anything meaningful that you can do about it. Trying to keep your program going is not useful, it cannot do the job it is supposed to do. In your case, there's no hope that the socket is ever going to receive data when there is no network. And, as you found out, trying to work around the problem just begets more problems. That's normal.
If this is bad practice, how can I implement it in a better way?
You need help from a human. The user is going to have to setup the machine to provide a working network connection. This requires a user interface, you must have a way to tell a human what he needs to do to solve your problem. You can make that as intricate or as simple as you desire. Just an error message, a verbatim copy of the Exception.Message can be enough. Writing an event handler for the AppDomain.CurrentDomain.UnhandledException event is a very good (and required) strategy. Microsoft spent an enormous amount of effort to make exception messages as clear and helpful as possible, even localizing them for you in the user's native language, you want to take advantage of that. Even if the exception message is mystifying, a quick Google query on the message text returns hundreds of hits. With this event handler in place, you don't have to do anything special. Your program automatically terminates and your user knows what to do about it.
You can certainly make it more intricate, you discovered that SetSocketOption() is liable to fail right after the network becomes available but works when you wait long enough. So this is actually an error condition that you can work around, just by waiting long enough. Whether you should write the code to handle this is something that you have to decide for yourself. It is something you write when you have enough experience with the way your program behaves, you never write it up front. Usually as a result from feedback from the users of your program.
Some good advice in the comments, lets' expand on it.
Firstly, I would put all this socket code in to its' own class, outside of the form. This makes it its' own entity and semantically easier to understand. This class could have a property Initialised, which is initially set to false. The first thing you do in your form is call an Initialise method on this class which attempts to set socket options and catches the relevant exceptions if the network is not available. If it is available, we set our Initialised property to true.
If not available, we set a single timeout (see System.Threading.Timer) that calls this same function (potentially with a retry count) after 'x' seconds. Once again we'll find ourselves back in this Initialise function, perhaps with a retry count mentioned at the beginning. Once again, if it is available, we're good - if not, set the timer again. Eventually, after 'x' retries if we're not initialised we can throw an exception or set some other failure property to indicate that we can't proceed.
Your Form class can periodically check (or hook in to an event) to determine whether the socket is now ready for communication. In case of failure you can gracefully quit out, or because our class is nice and abstracted, attempt to start the whole process again.
I'm building an application that uses Named Pipes for IPC.
When started writing a stress test, I found an issue related to when a client does quickly connect-disconnect.
Server code:
static void ServerThread()
{
var serverPipe = new NamedPipeServerStream("myipc", PipeDirection.InOut, -1, PipeTransmissionMode.Message, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
serverPipe.BeginWaitForConnection(
ar =>
{
var thisPipe = (NamedPipeServerStream)ar.AsyncState;
thisPipe.EndWaitForConnection(ar);
Task.Factory.StartNew(ServerThread);
thisPipe.Dispose();
},
serverPipe);
}
Client does nothing but connect-disconnect as follow:
static void RunClients()
{
for (int i = 0; i < 100; i++)
{
var clientPipe = new NamedPipeClientStream(".", "myipc", PipeDirection.InOut, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
clientPipe.Connect(1000);
clientPipe.Dispose();
}
}
When this runs, one of the clients is failing in Connect() while the server fails in BeginWaitForConnection - saying Pipe is being closed.
If I add at least Thread.Sleep(100) before each client disposes - everything works just fine.
I'm sure what I'm doing is a corner case, but I believe the pipes should be able to handle this in greaceful way.
Any ideas on what could be wrong?
Thanks!
one of the clients is failing in Connect()
Because the server immediately disposes the pipe after connecting.
the server fails in BeginWaitForConnection
Because the client immediately disposes the pipe after connecting.
I believe the pipes should be able to handle this in greaceful way.
It does, it gracefully throws an exception to let your code know that something exceptional happened. You seem to assume it is normal that code closes a pipe without doing anything to let the other end know that the pipe is about to disappear. That is not normal, it is exceptional. So you get an exceptional notification for it.
You catch exceptions with try/catch. There are two things you can do in your catch handler. You can assume that it is okay for code to close a pipe willy-nilly, in which case you do nothing beyond closing your end of the pipe and get out. Or you can assume that something Really Bad happened because the other end of the pipe didn't say goodbye nicely. Which is rather important to distinguish the oh-crap kind of mishaps, like a pipe client or the server crashing. It is up to you to choose your preferred way, but I strongly recommend to not ignore the oh-crap scenarios, it does and will happen. You just created a good simulation of such a mishap.
I'm writing a message layer for my distributed system. I'm using IOCP, ie the Socket.XXXAsync methods.
Here's something pretty close to what I'm doing (in fact, my receive function is based on his):
http://vadmyst.blogspot.com/2008/05/sample-code-for-tcp-server-using.html
What I've found now is that at the start of the program (two test servers talking to each other) I each time get a number of SAEA objects where the .Buffer is entirely filled with zeroes, yet the .BytesTransferred is the size of the buffer (1024 in my case).
What does this mean? Is there a special condition I need to check for? My system interprets this as an incomplete message and moves on, but I'm wondering if I'm actually missing some data. I was under the impression that if nothing was being received, you'd not get a callback. In any case, I can see in WireShark that there aren't any zero-length packets coming in.
I've found the following when I Googled it, but I'm not sure my problem is the same:
http://social.msdn.microsoft.com/Forums/en-US/ncl/thread/40fe397c-b1da-428e-a355-ee5a6b0b4d2c
http://go4answers.webhost4life.com/Example/socketasynceventargs-buffer-not-ready-121918.aspx
I am sure not what is going on in the linked example. It appears to be using asynchronous sockets in a synchronous way. I cannot see any callbacks or similar in the code. You may need to rethink whether you need synchronous or asynchronous sockets :).
To the problem at hand stems from the possibility that your functions are trying to read/write to the buffer before the network transmit/receive has been completed. Try using the callback functionality included in the async Socket. E.g.
// This goes into your accept function, to begin receiving the data
socketName.BeginReceive(yourbuffer, 0, yourbuffer.Length,
SocketFlags.None, new AsyncCallback(OnRecieveData), socketName);
// In your callback function you know that the socket has finished receiving data
// This callback will fire when the receive is complete.
private void OnRecieveData(IAsyncResult input) {
Socket inSocket = (Socket)input.AsyncState; // This is just a typecast
inSocket.EndReceive(input);
// Pull the data out of the socket as you already have before.
// state.Data.Write ......
}
There is a a single-threaded server using .NET Socket with TCP protocol, and Socket.Pool(), Socket.Select(), Socket.Receive().
To send, I used:
public void SendPacket(int clientid, byte[] packet)
{
clients[clientid].socket.Send(packet);
}
But it was very slow when sending a lot of data to one client (halting the whole main thread), so I replaced it with this:
public void SendPacket(int clientid, byte[] packet)
{
using (SocketAsyncEventArgs e = new SocketAsyncEventArgs())
{
e.SetBuffer(packet, 0, packet.Length);
clients[clientid].socket.SendAsync(e);
}
}
It works fine on Windows with .NET (I don't know if it's perfect), but on Linux with Mono, packets are either dropped or reordered (I don't know). Reverting to slow version with Socket.Send() works on Linux. Source for whole server.
How to write non-blocking SendPacket() function that works on Linux?
I'm going to take a guess that it has to do with your using statement and your SendAsync call. Perhaps e falls out of scope and is being disposed while SendAsync is still processing the buffer. But then this might throw an exception. I am really just taking a guess. Try removing the using statement and see what happens.
I would say by not abusing the async method. YOu will find nowhere a documentation stating that this acutally is forced to maintain order. it queues iem for a scheuler which get distributed to threads, and by ignoring that the oder is not maintained per documentation you open yourself up to implementation details.
The best possibly is to:
Have a queue per socket.
When you write dasta into this queue, and there is no worker thread, start a work item (ThreadPool) to process the thread.
This way you have separate distinct queues that maintain order. Only one thread will ever process one queue / socket.
I got the same problem; Linux and windows react not in the same way with SendAsync. Sometimes linux truncate the data, but there is a workaround. First of all you need to use a queue. Each time you use SendAsync you have to check the callback.
If e.Offset + e.BytesTransferred < e.Buffer.Length, you just have to e.SetBuffer(e.Offset + e.BytesTransferred, e.Buffer.Length - e.BytesTransferred - e.Offset); and call SendAsync again.
I dont know why mono-linux believe it's completed before sending all the data and it's strange but i'm sure he does.
just like #mathieu, 10y later, I can confirm on Unity Mono+Linux complete callback is called without all bytes being sent in some cases. For me it was large packets only.