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.
171 lines
5.4 KiB
171 lines
5.4 KiB
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
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|