Reputation: 16022
This send method will fail periodically because control is returned to the calling thread, and Send
is called again just as the socket is opened.
I am using Stephen Toub's class: http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
This causes the exception: A connect request was made on an already connected socket.
What's the correct approach to ensure that the asynchronous method doesn't suffer this fate. Basically the send cannot actually complete before the connection is made.
public async Task Send(byte[] tosend)
{
// this code is not correct / not thread safe.
if (this.socket.Connected)
await this.StartSending(tosend);
else
await StartConnecting(tosend);
}
private async Task StartSending(byte[] tosend)
{
var args = new SocketAsyncEventArgs();
args.SetBuffer(tosend, 0, tosend.Length);
var awaitable = new SocketAwaitable(args);
await this.socket.SendAsync(awaitable);
}
private async Task StartConnecting(byte[] tosend)
{
var local = Dns.GetHostEntry(Dns.GetHostName());
var ep = new IPEndPoint(local.AddressList.First(_ => _.AddressFamily == AddressFamily.InterNetwork), this.port);
var args = new SocketAsyncEventArgs() { RemoteEndPoint = ep };
var awaitable = new SocketAwaitable(args);
await this.socket.ConnectAsync(awaitable);
await StartSending(tosend);
}
my test just calls Send
very quickly in succession.
var sends = arrays.Select(_ => writer.Send(_)).ToArray();
Task.WaitAll(sends);
sometimes the code above works just fine, and the socket is connected, socket.Connected
is set to true 'on time'. Other times the call to this.socket.ConnectAsync
happens more than once.
Upvotes: 2
Views: 714
Reputation: 39872
The calls to Send
should be awaited, both so you know the connection has established and also so that you know that your data is being sent sequentially. This would better be handled by a foreach
loop than .Select
.
foreach (var data in arrays)
await writer.Send(data);
Presumably you create the variable sends
so that you can Task.WhenAll
on it. Unfortunately this won't work for the reason you already discovered. You could possibly solve this with a separate method called Connect
that async-ly connects to the remote host but does not send the data. You could then do:
await writer.Connect();
var sends = arrays.Select(_ => writer.Send(_)).ToArray();
Upvotes: 2