I'm designing a client-server chat application (in fact I'm not, but let's pretend I am:)), and I'm a bit puzzled by some race conditions I've experienced.
Let's say I've got the following code:
public interface IServer
{
[OperationContract(IsOneWay = false)]
[FaultContract(typeof(ChatException))]
void BroadcastMessage(string msg);
}
public class Server : IServer
{
void BroadcastMessage(string msg) // I'm not mentionning the try/catch/throw FaultException here for readability purposes
{
foreach (IClientCallback c in callbacks){
c.ReceiveMessage(msg);
}
}
}
public interface IClientCallback
{
[OperationContract(IsOneWay = true)]
void ReceiveMessage(string s);
}
And here is an excerpt of the binding configuration :
<endpoint address=""
binding="netTcpBinding"
bindingConfiguration="DuplexBinding"
contract="IServer" />
<binding name="DuplexBinding" sendTimeout="00:01:00">
<reliableSession ordered="true" inactivityTimeout="00:05:00" enabled="true"/>
<security mode="None">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
This is of course some sort of pseudo c#, I've removed a lot of non-relevant code for clarity sake.
Now to the point : This code won't work. When I call BroadcastMessage, the method never returns, and I eventually get a timeout on the client side. If I debug on the server side, everything seems fine (I return from the BroadcastMessage method exactly as one would expect, and I'm not blocking on any ReceiveMessage one way calls)
Here are two ways to fix this code :
- remove the FaultContract and declare the BroadcastMessage method as oneway=true
- Broadcast the message to everybody BUT the initial sender
My first guess was that the client side was waiting for the server to return, and thus wasn't available for handling the incoming ReceiveMessage call from the server, thus blocking the server, BUT ReceiveMessage is declared as oneway, and debugging the server shows that it doesn't block on any call to ReceiveMessage
Now, my questions :
What's going on?
Are there other ways to fix this? (maybe by tuning the binding configuration ?)
Let's say I choose fix 2 (ie don't broadcast back to the sender), what happens if the server calls my ReceiveMessage callback (because someone else sent me a message) while I'm waiting for my own BroadcastMessage call to finish?
I've read that OneWay calls are not totally oneway, and that the server still waits for an HTTP response from the other side. Any details on this? specifically, is the client able to respond suche http responses when it's blocked in a distant call?
Edit: Console .net 3.5 on the server side, Winforms .net 3.5 on the client side