You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
using Apewer.Internals; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading;
namespace Apewer.Network {
/// <summary>TCP 服务端。</summary>
public sealed class TcpServer : IDisposable {
Socket _server = null; List<Socket> _clients = new List<Socket>(1024);
/// <summary>获取当前监听的端口。</summary>
public int Port { get => GetLocalPort(); }
/// <summary>启动服务端,并在所有接口上监听端口。</summary>
public TcpServer(int port) : this(IPAddress.Any, port) { }
/// <summary>启动服务端,并监听端口。</summary>
public TcpServer(string ip, int port) : this(IPAddress.Parse(ip), port) { }
/// <summary>启动服务端,并监听端口。</summary>
public TcpServer(IPAddress address, int port) : this(new IPEndPoint(address, port)) { }
/// <summary>启动服务端,并监听端口。</summary>
public TcpServer(IPEndPoint endpoint) { _server = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _server.Bind(endpoint); _server.Listen(500); _server.SendTimeout = 5000; }
/// <summary>关闭连接,释放系统资源。</summary>
public void Dispose() { lock (_clients) { foreach (var client in _clients) { try { client.Disconnect(false); } catch { } try { client.Close(100); } catch { } #if !NET20
try { client.Dispose(); } catch { } #endif
} _clients.Clear(); } if (_server != null) { try { _server.Disconnect(false); } catch { } try { _server.Close(100); } catch { } #if !NET20
try { _server.Dispose(); } catch { } #endif
} }
/// <summary>获取当前所有客户端连接。</summary>
public Socket[] GetClients() { lock (_clients) { var array = _clients.ToArray(); return array; } }
/// <summary>等待接收客户端连接。此方法将会阻塞当前线程直到关闭监听的端口。</summary>
/// <param name="callback">处理客户端连接,当此回调结束时将释放此连接。</param>
/// <exception cref="ArgumentNullException"></exception>
public void Accept(Action<Socket> callback) { if (callback == null) throw new ArgumentNullException(nameof(callback));
while (true) { var socket = null as Socket; try { socket = _server.Accept(); if (socket != null) { Callback.Enqueue(this, socket, callback); } } catch { if (socket != null) { try { socket.Close(); } catch { } try { socket.Disconnect(false); } catch { } #if !NET20
try { socket.Dispose(); } catch { } #endif
} } } }
int GetLocalPort() { var socket = _server; if (socket != null) { var endpoint = socket.LocalEndPoint as IPEndPoint; if (endpoint != null) return endpoint.Port; } return 0; }
sealed class Callback {
TcpServer _server; Socket _socket; Action<Socket> _action;
public static void Enqueue(TcpServer server, Socket socket, Action<Socket> callback) { var state = new Callback(); state._server = server ?? throw new ArgumentNullException(nameof(server)); state._socket = socket ?? throw new ArgumentNullException(nameof(socket)); state._action = callback ?? throw new ArgumentNullException(nameof(callback));
ThreadPool.QueueUserWorkItem(InThreadPool, state); }
static void InThreadPool(object state) { var instance = state as Callback; if (instance == null) return; if (instance._server == null) return; if (instance._socket == null) return; if (instance._action == null) return;
var socket = instance._socket; lock (instance._server._clients) { instance._server._clients.Add(instance._socket); } try { instance._action.Invoke(instance._socket); } catch { } finally { lock (instance._server._clients) { instance._server._clients.Remove(instance._socket); } try { socket.Disconnect(false); } catch { } try { socket.Close(100); } catch { } #if !NET20
try { socket.Dispose(); } catch { } #endif
} }
}
}
}
|