Skip to content

Commit fcc4add

Browse files
committed
More robust communication with keep-alive pings
1 parent 105d943 commit fcc4add

File tree

2 files changed

+171
-140
lines changed

2 files changed

+171
-140
lines changed

SimplSockets/SimplSocketClient.cs

+89-83
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,7 @@ public void Connect(EndPoint endPoint)
140140
}
141141
catch (SocketException ex)
142142
{
143-
lock (_isConnectedLock)
144-
{
145-
if (_isConnected)
146-
{
147-
HandleCommunicationError(_socket, ex);
148-
_isConnected = false;
149-
}
150-
}
143+
HandleCommunicationError(_socket, ex);
151144
}
152145
catch (ObjectDisposedException)
153146
{
@@ -179,14 +172,7 @@ public void Send(byte[] message)
179172
}
180173
catch (SocketException ex)
181174
{
182-
lock (_isConnectedLock)
183-
{
184-
if (_isConnected)
185-
{
186-
HandleCommunicationError(_socket, ex);
187-
_isConnected = false;
188-
}
189-
}
175+
HandleCommunicationError(_socket, ex);
190176
}
191177
catch (ObjectDisposedException)
192178
{
@@ -222,15 +208,7 @@ public byte[] SendReceive(byte[] message)
222208
}
223209
catch (SocketException ex)
224210
{
225-
lock (_isConnectedLock)
226-
{
227-
if (_isConnected)
228-
{
229-
HandleCommunicationError(_socket, ex);
230-
_isConnected = false;
231-
}
232-
}
233-
211+
HandleCommunicationError(_socket, ex);
234212
return null;
235213
}
236214
catch (ObjectDisposedException)
@@ -273,10 +251,7 @@ public void Close()
273251
_socket.Close();
274252

275253
// No longer connected
276-
lock (_isConnectedLock)
277-
{
278-
_isConnected = false;
279-
}
254+
_isConnected = false;
280255
}
281256

282257
/// <summary>
@@ -322,15 +297,7 @@ private void ConnectCallback(IAsyncResult asyncResult)
322297
}
323298
catch (SocketException ex)
324299
{
325-
lock (_isConnectedLock)
326-
{
327-
if (_isConnected)
328-
{
329-
HandleCommunicationError(_socket, ex);
330-
_isConnected = false;
331-
}
332-
}
333-
300+
HandleCommunicationError(_socket, ex);
334301
return;
335302
}
336303
catch (ObjectDisposedException)
@@ -355,13 +322,55 @@ private void ConnectCallback(IAsyncResult asyncResult)
355322
// Post a receive to the socket as the client will be continuously receiving messages to be pushed to the queue
356323
_socket.BeginReceive(messageState.Buffer, 0, messageState.Buffer.Length, 0, ReceiveCallback, messageState);
357324

325+
// Spin up the keep-alive
326+
KeepAlive(_socket);
327+
358328
// Process all incoming messages
359329
var processMessageState = _messageStatePool.Pop();
360330
processMessageState.Handler = _socket;
361331

362332
ProcessReceivedMessage(processMessageState);
363333
}
364334

335+
private void KeepAlive(Socket handler)
336+
{
337+
int availableTest = 0;
338+
339+
// If the socket is disposed, we're done
340+
try
341+
{
342+
availableTest = handler.Available;
343+
}
344+
catch (ObjectDisposedException)
345+
{
346+
// Peace out!
347+
return;
348+
}
349+
350+
// Do the keep-alive
351+
try
352+
{
353+
handler.BeginSend(_controlBytesPlaceholder, 0, _controlBytesPlaceholder.Length, 0, KeepAliveCallback, handler);
354+
}
355+
catch (SocketException ex)
356+
{
357+
HandleCommunicationError(handler, ex);
358+
}
359+
catch (ObjectDisposedException)
360+
{
361+
// If disposed, handle communication error was already done and we're just catching up on other threads. Supress it.
362+
}
363+
}
364+
365+
private void KeepAliveCallback(IAsyncResult asyncResult)
366+
{
367+
SendCallback(asyncResult);
368+
369+
Thread.Sleep(1000);
370+
371+
KeepAlive((Socket)asyncResult.AsyncState);
372+
}
373+
365374
private void SendCallback(IAsyncResult asyncResult)
366375
{
367376
// Get the socket to complete on
@@ -374,15 +383,7 @@ private void SendCallback(IAsyncResult asyncResult)
374383
}
375384
catch (SocketException ex)
376385
{
377-
lock (_isConnectedLock)
378-
{
379-
if (_isConnected)
380-
{
381-
HandleCommunicationError(_socket, ex);
382-
_isConnected = false;
383-
}
384-
}
385-
386+
HandleCommunicationError(_socket, ex);
386387
return;
387388
}
388389
catch (ObjectDisposedException)
@@ -405,15 +406,7 @@ private void ReceiveCallback(IAsyncResult asyncResult)
405406
}
406407
catch (SocketException ex)
407408
{
408-
lock (_isConnectedLock)
409-
{
410-
if (_isConnected)
411-
{
412-
HandleCommunicationError(_socket, ex);
413-
_isConnected = false;
414-
}
415-
}
416-
409+
HandleCommunicationError(_socket, ex);
417410
return;
418411
}
419412
catch (ObjectDisposedException)
@@ -491,27 +484,34 @@ private void ProcessReceivedMessage(MessageState messageState)
491484

492485
// Have control bytes, get message bytes
493486

494-
// Initialize buffer if needed
495-
if (messageState.Buffer == null)
487+
// SPECIAL CASE: if empty message, skip a bunch of stuff
488+
if (messageState.BytesToRead != 0)
496489
{
497-
messageState.Buffer = new byte[messageState.BytesToRead];
498-
}
490+
// Initialize buffer if needed
491+
if (messageState.Buffer == null)
492+
{
493+
messageState.Buffer = new byte[messageState.BytesToRead];
494+
}
499495

500-
var bytesAvailable = bytesRead - currentOffset;
496+
var bytesAvailable = bytesRead - currentOffset;
501497

502-
var bytesToCopy = Math.Min(messageState.BytesToRead, bytesAvailable);
498+
var bytesToCopy = Math.Min(messageState.BytesToRead, bytesAvailable);
503499

504-
// Copy bytes to buffer
505-
Buffer.BlockCopy(buffer, currentOffset, messageState.Buffer, messageState.Buffer.Length - messageState.BytesToRead, bytesToCopy);
500+
// Copy bytes to buffer
501+
Buffer.BlockCopy(buffer, currentOffset, messageState.Buffer, messageState.Buffer.Length - messageState.BytesToRead, bytesToCopy);
506502

507-
currentOffset += bytesToCopy;
508-
messageState.BytesToRead -= bytesToCopy;
503+
currentOffset += bytesToCopy;
504+
messageState.BytesToRead -= bytesToCopy;
505+
}
509506

510507
// Check if we're done
511508
if (messageState.BytesToRead == 0)
512509
{
513-
// Done, add to complete received messages
514-
CompleteMessage(messageState.Handler, messageState.ThreadId, messageState.Buffer);
510+
if (messageState.Buffer != null)
511+
{
512+
// Done, add to complete received messages
513+
CompleteMessage(messageState.Handler, messageState.ThreadId, messageState.Buffer);
514+
}
515515

516516
// Reset message state
517517
messageState.Buffer = null;
@@ -566,24 +566,30 @@ private void CompleteMessage(Socket handler, int threadId, byte[] message)
566566
/// <param name="ex">The exception that the socket raised.</param>
567567
private void HandleCommunicationError(Socket socket, Exception ex)
568568
{
569-
// Close the socket
570-
try
571-
{
572-
socket.Shutdown(SocketShutdown.Both);
573-
}
574-
catch (SocketException)
569+
lock (socket)
575570
{
576-
// Socket was not able to be shutdown, likely because it was never opened
577-
}
578-
catch (ObjectDisposedException)
579-
{
580-
// Socket was already closed/disposed, so return out to prevent raising the Error event multiple times
581-
// This is most likely to happen when an error occurs during heavily multithreaded use
582-
return;
571+
// Close the socket
572+
try
573+
{
574+
socket.Shutdown(SocketShutdown.Both);
575+
}
576+
catch (SocketException)
577+
{
578+
// Socket was not able to be shutdown, likely because it was never opened
579+
}
580+
catch (ObjectDisposedException)
581+
{
582+
// Socket was already closed/disposed, so return out to prevent raising the Error event multiple times
583+
// This is most likely to happen when an error occurs during heavily multithreaded use
584+
return;
585+
}
586+
587+
// Close / dispose the socket
588+
socket.Close();
583589
}
584590

585-
// Close / dispose the socket
586-
socket.Close();
591+
// No longer connected
592+
_isConnected = false;
587593

588594
// Clear receive queue for this client
589595
_receiveBufferQueue.Clear();

0 commit comments

Comments
 (0)