/// <summary> /// Releases the Stream's SocketAsyncEventArgs back to the pool, /// and free's up another slot for a new client to connect /// </summary> /// <param name="Stream">The GamespyTcpStream object that is being released.</param> public void Release(GamespyTcpStream Stream) { // If the stream has been released, then we stop here if (!IsListening || Stream.Released) { return; } // Make sure the connection is closed properly if (!Stream.SocketClosed) { Stream.Close(); return; } // To prevent cross instance releasing if (!Object.ReferenceEquals(this, Stream.SocketManager)) { throw new ArgumentException("Cannot pass a GamespyTcpStream belonging to a different TcpSocket than this one."); } // If we are still registered for this event, then the EventArgs should // NEVER be disposed here, or we have an error to fix if (Stream.DisposedEventArgs) { // Log this error Program.ErrorLog.Write("WARNING: [GamespyTcpSocket.Release] Event Args were disposed imporperly!"); // Dispose old buffer tokens BufferManager.ReleaseBuffer(Stream.ReadEventArgs); BufferManager.ReleaseBuffer(Stream.WriteEventArgs); // Create new Read Event Args SocketAsyncEventArgs SockArgR = new SocketAsyncEventArgs(); BufferManager.AssignBuffer(SockArgR); SocketReadWritePool.Push(SockArgR); // Create new Write Event Args SocketAsyncEventArgs SockArgW = new SocketAsyncEventArgs(); BufferManager.AssignBuffer(SockArgW); SocketReadWritePool.Push(SockArgW); } else { // Set null's Stream.ReadEventArgs.AcceptSocket = null; Stream.WriteEventArgs.AcceptSocket = null; // Get our ReadWrite AsyncEvent object back SocketReadWritePool.Push(Stream.ReadEventArgs); SocketReadWritePool.Push(Stream.WriteEventArgs); } // Now that we have another set of AsyncEventArgs, we can // release this users Semephore lock, allowing another connection MaxConnectionsEnforcer.Release(); }
/// <summary> /// Creates a new UDP socket for handling Gamespy Protocol /// </summary> /// <param name="Port">The port this socket will be bound to</param> /// <param name="MaxConnections">The maximum number of concurrent connections</param> public GamespyUdpSocket(int Port, int MaxConnections) { // Create our Socket this.Port = Port; Listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) { SendTimeout = 5000, // We have a limited pool, so we dont want to be locked often SendBufferSize = BufferSizePerEvent, ReceiveBufferSize = BufferSizePerEvent }; // Bind to our port Listener.Bind(new IPEndPoint(IPAddress.Any, Port)); // Set the rest of our internals MaxNumConnections = MaxConnections; MaxConnectionsEnforcer = new SemaphoreSlim(MaxNumConnections, MaxNumConnections); SocketReadWritePool = new SocketAsyncEventArgsPool(MaxNumConnections); // Create our Buffer Manager for IO operations. BufferManager = new BufferManager(MaxNumConnections, BufferSizePerEvent); // Assign our Connection IO SocketAsyncEventArgs object instances for (int i = 0; i < MaxNumConnections; i++) { SocketAsyncEventArgs SockArg = new SocketAsyncEventArgs(); SockArg.Completed += IOComplete; BufferManager.AssignBuffer(SockArg); SocketReadWritePool.Push(SockArg); } // set public internals IsRunning = true; IsDisposed = false; }
/// <summary> /// Creates a new TCP socket for handling Gamespy Protocol /// </summary> /// <param name="Port">The port this socket will be bound to</param> /// <param name="MaxConnections">The maximum number of concurrent connections</param> public GamespyTcpSocket(int Port, int MaxConnections) { // Create our Socket Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Set Socket options Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, false); Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); // Bind to our port Listener.Bind(new IPEndPoint(IPAddress.Any, Port)); Listener.Listen(25); // Set the rest of our internals MaxNumConnections = MaxConnections; MaxConnectionsEnforcer = new SemaphoreSlim(MaxNumConnections, MaxNumConnections); SocketAcceptPool = new SocketAsyncEventArgsPool(ConcurrentAcceptPoolSize); SocketReadWritePool = new SocketAsyncEventArgsPool(MaxNumConnections); // Create our Buffer Manager for IO operations. // Always allocate double space, one for recieving, and another for sending BufferManager = new BufferManager(MaxNumConnections * 2, BufferSizePerEventArg); // Assign our Connection Accept SocketAsyncEventArgs object instances for (int i = 0; i < ConcurrentAcceptPoolSize; i++) { SocketAsyncEventArgs SockArg = new SocketAsyncEventArgs(); SockArg.Completed += (s, e) => PrepareAccept(e); // Do NOT assign buffer space for Accept operations! // AcceptAsync does not take require a parameter for buffer size. SocketAcceptPool.Push(SockArg); } // Assign our Connection IO SocketAsyncEventArgs object instances for (int i = 0; i < MaxNumConnections * 2; i++) { SocketAsyncEventArgs SockArg = new SocketAsyncEventArgs(); BufferManager.AssignBuffer(SockArg); SocketReadWritePool.Push(SockArg); } // set public internals IsListening = true; IgnoreNewConnections = false; IsDisposed = false; }
public TCPServer(string serverName, IPEndPoint bindTo, int MaxConnections) { ServerName = "[" + serverName + "]"; // Create our Socket Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Set Socket options Listener.LingerState = new LingerOption(enable: false, seconds: 0); Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); // Bind to our port Listener.Bind(bindTo); Listener.Listen(25); // Set the rest of our internals MaxNumConnections = MaxConnections; MaxConnectionsEnforcer = new SemaphoreSlim(MaxNumConnections, MaxNumConnections); SocketAcceptPool = new SocketAsyncEventArgsPool(ConcurrentAcceptPoolSize); SocketReadWritePool = new SocketAsyncEventArgsPool(MaxNumConnections * 2); // Create our Buffer Manager for IO operations. // Always allocate double space, one for recieving, and another for sending BufferManager = new BufferManager(MaxNumConnections * 2, BufferSizePerOperation); // Assign our Connection Accept SocketAsyncEventArgs object instances for (int i = 0; i < ConcurrentAcceptPoolSize; i++) { SocketAsyncEventArgs SockArg = new SocketAsyncEventArgs(); SockArg.Completed += (s, e) => PrepareAccept(e); // Do NOT assign buffer space for Accept operations! SocketAcceptPool.Push(SockArg); } // Assign our Connection IO SocketAsyncEventArgs object instances for (int i = 0; i < MaxNumConnections * 2; i++) { SocketAsyncEventArgs SockArg = new SocketAsyncEventArgs(); BufferManager.AssignBuffer(SockArg); SocketReadWritePool.Push(SockArg); } // set public internals IsListening = true; }