Skip to content

Commit

Permalink
A few more bug fixes regarding infinite thread hands
Browse files Browse the repository at this point in the history
  • Loading branch information
haneytron committed Dec 12, 2013
1 parent d836ab8 commit 6445969
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 30 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A spinoff library of Dache that provides highly efficient, scalable, simple sock

**NUGET:** http://www.nuget.org/packages/SimplSockets

**WEB:** http://www.getdache.net
**WEB:** http://www.getdache.net

**EMAIL:** info@getdache.net

Expand All @@ -15,6 +15,23 @@ VERSION HISTORY
============================================


1.1.0
------------------


- Fixed multiple bugs in how SimplSocket class handled communication errors.

- Fixed bugs that could cause infinite client hang in the case that the server stopped responding.

- Fixed semaphore calculation bugs.

- Errors are now handled gracefully and correctly, with atomic exception raising via the passed in error handler event delegate.

- Slight performance improvements enabled by smoother connection error handling.

- Special thanks to Ruslan (https://github.com/ruzhovt) for discovering and documenting the source of these errors.


1.0.1
------------------

Expand Down
6 changes: 2 additions & 4 deletions SimplSockets/ISimplSocketClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ namespace SimplSockets
public interface ISimplSocketClient : IDisposable
{
/// <summary>
/// Connects to an endpoint. Once this is called, you must call Close before calling Connect or Listen again. The errorHandler method
/// will not be called if the connection fails. Instead this method will return false.
/// Connects to an endpoint. Once this is called, you must call Close before calling Connect or Listen again. This method will not raise an error.
/// </summary>
/// <param name="endPoint">The endpoint.</param>
/// <param name="errorHandler">The error handler.</param>
/// <returns>true if connection is successful, false otherwise.</returns>
bool Connect(EndPoint endPoint, EventHandler<SocketErrorArgs> errorHandler);
bool Connect(EndPoint endPoint);

/// <summary>
/// Sends a message to the server without waiting for a response (one-way communication).
Expand Down
3 changes: 1 addition & 2 deletions SimplSockets/ISimplSocketServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ public interface ISimplSocketServer : IDisposable
/// Begin listening for incoming connections. Once this is called, you must call Close before calling Connect or Listen again.
/// </summary>
/// <param name="localEndpoint">The local endpoint to listen on.</param>
/// <param name="errorHandler">The error handler.</param>
void Listen(EndPoint localEndpoint, EventHandler<SocketErrorArgs> errorHandler);
void Listen(EndPoint localEndpoint);

/// <summary>
/// Sends a message back to the client.
Expand Down
49 changes: 26 additions & 23 deletions SimplSockets/SimplSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,40 +58,57 @@ public class SimplSocket : ISimplSocketClient, ISimplSocketServer, IDisposable
/// Create a client.
/// </summary>
/// <param name="socketFunc">The function that creates a new socket. Use this to specify your socket constructor and initialize settings.</param>
/// <param name="errorHandler">The error handler that is raised when a Socket error occurs.</param>
/// <param name="messageBufferSize">The message buffer size to use for send/receive.</param>
/// <param name="maximumConnections">The maximum connections to allow to use the socket simultaneously.</param>
/// <param name="useNagleAlgorithm">Whether or not to use the Nagle algorithm.</param>
public static ISimplSocketClient CreateClient(Func<Socket> socketFunc, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
public static ISimplSocketClient CreateClient(Func<Socket> socketFunc, EventHandler<SocketErrorArgs> errorHandler, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
{
return new SimplSocket(socketFunc, messageBufferSize, maximumConnections, useNagleAlgorithm);
return new SimplSocket(socketFunc, errorHandler, messageBufferSize, maximumConnections, useNagleAlgorithm);
}

/// <summary>
/// Create a server.
/// </summary>
/// <param name="socketFunc">The function that creates a new socket. Use this to specify your socket constructor and initialize settings.</param>
/// <param name="errorHandler">The error handler that is raised when a Socket error occurs.</param>
/// <param name="messageHandler">The message handler that handles incoming messages.</param>
/// <param name="messageBufferSize">The message buffer size to use for send/receive.</param>
/// <param name="maximumConnections">The maximum connections to allow to use the socket simultaneously.</param>
/// <param name="useNagleAlgorithm">Whether or not to use the Nagle algorithm.</param>
public static ISimplSocketServer CreateServer(Func<Socket> socketFunc, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
public static ISimplSocketServer CreateServer(Func<Socket> socketFunc, EventHandler<SocketErrorArgs> errorHandler, EventHandler<MessageReceivedArgs> messageHandler,
int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
{
return new SimplSocket(socketFunc, messageBufferSize, maximumConnections, useNagleAlgorithm);
// Sanitize
if (messageHandler == null)
{
throw new ArgumentNullException("messageHandler");
}

var simplSocket = new SimplSocket(socketFunc, errorHandler, messageBufferSize, maximumConnections, useNagleAlgorithm);
simplSocket.MessageReceived += messageHandler;
return simplSocket;
}

/// <summary>
/// The private constructor - used to enforce factor-style instantiation.
/// </summary>
/// <param name="socketFunc">The function that creates a new socket. Use this to specify your socket constructor and initialize settings.</param>
/// <param name="errorHandler">The error handler that is raised when a Socket error occurs.</param>
/// <param name="messageBufferSize">The message buffer size to use for send/receive.</param>
/// <param name="maximumConnections">The maximum connections to allow to use the socket simultaneously.</param>
/// <param name="useNagleAlgorithm">Whether or not to use the Nagle algorithm.</param>
private SimplSocket(Func<Socket> socketFunc, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
private SimplSocket(Func<Socket> socketFunc, EventHandler<SocketErrorArgs> errorHandler, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
{
// Sanitize
if (socketFunc == null)
{
throw new ArgumentNullException("socketFunc");
}
if (errorHandler == null)
{
throw new ArgumentNullException("errorHandler");
}
if (messageBufferSize < 128)
{
throw new ArgumentException("must be >= 128", "messageBufferSize");
Expand All @@ -102,6 +119,7 @@ private SimplSocket(Func<Socket> socketFunc, int messageBufferSize, int maximumC
}

_socketFunc = socketFunc;
Error += errorHandler;
_messageBufferSize = messageBufferSize;
_maximumConnections = maximumConnections;
_maxConnectionsSemaphore = new Semaphore(maximumConnections, maximumConnections);
Expand Down Expand Up @@ -158,9 +176,8 @@ public int CurrentlyConnectedClients
/// will not be called if the connection fails. Instead this method will return false.
/// </summary>
/// <param name="endPoint">The endpoint.</param>
/// <param name="errorHandler">The error handler.</param>
/// <returns>true if connection is successful, false otherwise.</returns>
public bool Connect(EndPoint endPoint, EventHandler<SocketErrorArgs> errorHandler)
public bool Connect(EndPoint endPoint)
{
// Sanitize
if (_isDoingSomething)
Expand All @@ -171,10 +188,6 @@ public bool Connect(EndPoint endPoint, EventHandler<SocketErrorArgs> errorHandle
{
throw new ArgumentNullException("endPoint");
}
if (errorHandler == null)
{
throw new ArgumentNullException("errorHandler");
}

_isDoingSomething = true;
_useClientMultiplexer = true;
Expand All @@ -196,12 +209,10 @@ public bool Connect(EndPoint endPoint, EventHandler<SocketErrorArgs> errorHandle
}
catch (SocketException ex)
{
_isDoingSomething = false;
return false;
}

// Register error handler
Error += errorHandler;

// Get a message state from the pool
var messageState = _messageStatePool.Pop();
messageState.Data = new MemoryStream();
Expand Down Expand Up @@ -233,8 +244,7 @@ public bool Connect(EndPoint endPoint, EventHandler<SocketErrorArgs> errorHandle
/// Begin listening for incoming connections. Once this is called, you must call Close before calling Connect or Listen again.
/// </summary>
/// <param name="localEndpoint">The local endpoint to listen on.</param>
/// <param name="errorHandler">The error handler.</param>
public void Listen(EndPoint localEndpoint, EventHandler<SocketErrorArgs> errorHandler)
public void Listen(EndPoint localEndpoint)
{
// Sanitize
if (_isDoingSomething)
Expand All @@ -245,16 +255,9 @@ public void Listen(EndPoint localEndpoint, EventHandler<SocketErrorArgs> errorHa
{
throw new ArgumentNullException("localEndpoint");
}
if (errorHandler == null)
{
throw new ArgumentNullException("errorHandler");
}

_isDoingSomething = true;

// Register error handler
Error += errorHandler;

// Create socket
_socket = _socketFunc();

Expand Down

0 comments on commit 6445969

Please sign in to comment.