c#有什么好用的socket框架么?

列车
  • 47

想用c#编写tcp的服务端,C#下有什么好用的socket框架?c#自带的tcp服务端好像是TcpListener

回复
阅读 1.4k
4 个回答
_60976338c0fc3
  • 2
新手上路,请多包涵
C#下有什么好用的socket框架?

我不知道。

UDP: System.Net.Sockets.UdpClient
TCP: System.Net.Sockets.TcpClient, System.Net.Sockets.TcpListener

没有好用的框架是因为自带的已经足够强大了,大家都没动力写。
不是太复杂,没有高性能要求的话,这些够用了。
Websocket框架有一些,但是到.net core时代也基本都停更了。

贴一个我用的,也是在网上找的,可能有bug,生产环境谨慎使用!

/// <summary>
/// 异步TCP服务器
/// </summary>
public class AsyncTcpServer : IDisposable
{
    #region Fields

    private TcpListener listener;
    private List<TcpClientState> clients;
    private bool disposed = false;

    #endregion

    #region Ctors

    /// <summary>
    /// 异步TCP服务器
    /// </summary>
    /// <param name="listenPort">监听的端口</param>
    public AsyncTcpServer(int listenPort) : this(IPAddress.Any, listenPort)
    {
    }

    /// <summary>
    /// 异步TCP服务器
    /// </summary>
    /// <param name="localEP">监听的终结点</param>
    public AsyncTcpServer(IPEndPoint localEP) : this(localEP.Address, localEP.Port)
    {
    }

    /// <summary>
    /// 异步TCP服务器
    /// </summary>
    /// <param name="localIPAddress">监听的IP地址</param>
    /// <param name="listenPort">监听的端口</param>
    public AsyncTcpServer(IPAddress localIPAddress, int listenPort)
    {
        Address = localIPAddress;
        Port = listenPort;
        this.Encoding = Encoding.Default;

        clients = new List<TcpClientState>();

        listener = new TcpListener(Address, Port);
        listener.AllowNatTraversal(true);
    }

    #endregion

    #region Properties

    /// <summary>
    /// 服务器是否正在运行
    /// </summary>
    public bool IsRunning { get; private set; }

    /// <summary>
    /// 监听的IP地址
    /// </summary>
    public IPAddress Address { get; private set; }

    /// <summary>
    /// 监听的端口
    /// </summary>
    public int Port { get; private set; }

    /// <summary>
    /// 通信使用的编码
    /// </summary>
    public Encoding Encoding { get; set; }

    #endregion

    #region Server

    /// <summary>
    /// 启动服务器
    /// </summary>
    /// <returns>异步TCP服务器</returns>
    public AsyncTcpServer Start()
    {
        if (!IsRunning)
        {
            IsRunning = true;
            listener.Start();
            listener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), listener);
        }
        return this;
    }

    /// <summary>
    /// 启动服务器
    /// </summary>
    /// <param name="backlog">
    /// 服务器所允许的挂起连接序列的最大长度
    /// </param>
    /// <returns>异步TCP服务器</returns>
    public AsyncTcpServer Start(int backlog)
    {
        if (!IsRunning)
        {
            IsRunning = true;
            listener.Start(backlog);
            listener.BeginAcceptTcpClient(
                new AsyncCallback(HandleTcpClientAccepted), listener);
        }
        return this;
    }

    /// <summary>
    /// 停止服务器
    /// </summary>
    /// <returns>异步TCP服务器</returns>
    public AsyncTcpServer Stop()
    {
        if (IsRunning)
        {
            IsRunning = false;

            lock (this.clients)
            {
                for (int i = 0; i < this.clients.Count; i++)
                {
                    this.clients[i].Close();
                }
                this.clients.Clear();
            }

            listener.Stop();
        }
        return this;
    }

    #endregion

    #region Receive

    private void HandleTcpClientAccepted(IAsyncResult ar)
    {
        if (!IsRunning) return;

        TcpListener tcpListener = (TcpListener)ar.AsyncState;
        TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar);

        byte[] buffer = new byte[tcpClient.ReceiveBufferSize];
        TcpClientState internalClient = new TcpClientState(tcpClient, buffer);
        lock (this.clients)
        {
            this.clients.Add(internalClient);
            RaiseClientConnected(tcpClient);
        }

        var networkStream = internalClient.Stream;
        networkStream.BeginRead(internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient);

        tcpListener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState);
    }

    private void HandleDatagramReceived(IAsyncResult ar)
    {
        if (!IsRunning) return;

        TcpClientState internalClient = (TcpClientState)ar.AsyncState;
        NetworkStream networkStream = internalClient.Stream;

        int numberOfReadBytes = 0;
        try
        {
            numberOfReadBytes = networkStream.EndRead(ar);
        }
        catch
        {
            numberOfReadBytes = 0;
        }

        if (numberOfReadBytes == 0)
        {
            // connection has been closed
            lock (this.clients)
            {
                this.clients.Remove(internalClient);
                RaiseClientDisconnected(internalClient.Client);
                return;
            }
        }

        // received byte and trigger event notification
        byte[] receivedBytes = new byte[numberOfReadBytes];
        Buffer.BlockCopy(internalClient.Buffer, 0, receivedBytes, 0, numberOfReadBytes);
        RaiseDatagramReceived(internalClient.Client, receivedBytes);
        RaisePlaintextReceived(internalClient.Client, receivedBytes);

        // continue listening for tcp datagram packets
        networkStream.BeginRead(internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient);
    }

    #endregion

    #region Events

    /// <summary>
    /// 接收到数据报文事件
    /// </summary>
    public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived;
    /// <summary>
    /// 接收到数据报文明文事件
    /// </summary>
    public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived;

    private void RaiseDatagramReceived(TcpClient sender, byte[] datagram)
    {
        DatagramReceived?.Invoke(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram));
    }

    private void RaisePlaintextReceived(TcpClient sender, byte[] datagram)
    {
        PlaintextReceived?.Invoke(this, new TcpDatagramReceivedEventArgs<string>(sender, this.Encoding.GetString(datagram, 0, datagram.Length)));
    }

    /// <summary>
    /// 与客户端的连接已建立事件
    /// </summary>
    public event EventHandler<TcpClientConnectedEventArgs> ClientConnected;
    /// <summary>
    /// 与客户端的连接已断开事件
    /// </summary>
    public event EventHandler<TcpClientDisconnectedEventArgs> ClientDisconnected;

    private void RaiseClientConnected(TcpClient tcpClient)
    {
        if (ClientConnected != null)
        {
            ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient));
        }
    }

    private void RaiseClientDisconnected(TcpClient tcpClient)
    {
        ClientDisconnected?.Invoke(this, new TcpClientDisconnectedEventArgs(tcpClient));
    }

    #endregion

    #region Send

    /// <summary>
    /// 发送报文至指定的客户端
    /// </summary>
    /// <param name="tcpClient">客户端</param>
    /// <param name="datagram">报文</param>
    public void Send(TcpClient tcpClient, byte[] datagram)
    {
        if (!IsRunning)
            throw new InvalidProgramException("This TCP server has not been started.");

        if (tcpClient == null)
            throw new ArgumentNullException("tcpClient");

        if (datagram == null)
            throw new ArgumentNullException("datagram");

        tcpClient.GetStream().BeginWrite(
            datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient);
    }

    private void HandleDatagramWritten(IAsyncResult ar)
    {
        ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);
    }

    /// <summary>
    /// 发送报文至指定的客户端
    /// </summary>
    /// <param name="tcpClient">客户端</param>
    /// <param name="datagram">报文</param>
    public void Send(TcpClient tcpClient, string datagram)
    {
        Send(tcpClient, this.Encoding.GetBytes(datagram));
    }

    /// <summary>
    /// 发送报文至所有客户端
    /// </summary>
    /// <param name="datagram">报文</param>
    public void SendAll(byte[] datagram)
    {
        if (!IsRunning)
            throw new InvalidProgramException("This TCP server has not been started.");

        for (int i = 0; i < this.clients.Count; i++)
        {
            Send(this.clients[i].Client, datagram);
        }
    }

    /// <summary>
    /// 发送报文至所有客户端
    /// </summary>
    /// <param name="datagram">报文</param>
    public void SendAll(string datagram)
    {
        if (!IsRunning)
            throw new InvalidProgramException("This TCP server has not been started.");

        SendAll(this.Encoding.GetBytes(datagram));
    }

    #endregion

    #region IDisposable Members

    /// <summary>
    /// Performs application-defined tasks associated with freeing, 
    /// releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Releases unmanaged and - optionally - managed resources
    /// </summary>
    /// <param name="disposing"><c>true</c> to release 
    /// both managed and unmanaged resources; <c>false</c> 
    /// to release only unmanaged resources.</param>
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                try
                {
                    Stop();

                    if (listener != null)
                    {
                        listener = null;
                    }
                }
                catch (SocketException)
                {
                }
            }

            disposed = true;
        }
    }

    #endregion
}

public class TcpClientState
{
    public byte[] Buffer { get; private set; }

    public TcpClient Client { get; private set; }

    public NetworkStream Stream => Client.GetStream();

    public TcpClientState(TcpClient tcpClient, byte[] buffer)
    {
        this.Client = tcpClient;
        this.Buffer = buffer;
    }

    public void Close()
    {
        if (Client == null) return;

        try
        {
            Client.Client.Disconnect(false);
            Client.Client.Close();
            Stream.Close();
            Client.Close();
            Client = null;
        }
        catch (System.ObjectDisposedException)
        {
            return;
        }
        catch (System.InvalidOperationException)
        {
            return;
        }
        catch (Exception ex)
        {
            Logger.Instance.WriteException(ex);
        }
    }
}


public class TcpDatagramReceivedEventArgs<T> : EventArgs
{
    public TcpClient TcpClient { set; get; }

    public T Datagram { set; get; }

    public TcpDatagramReceivedEventArgs(TcpClient tcpClient, T datagram)
    {
        this.TcpClient = tcpClient;
        this.Datagram = datagram;
    }
}


public class TcpClientConnectedEventArgs : EventArgs
{
    public TcpClient TcpClient { get; set; }

    public TcpClientConnectedEventArgs(TcpClient tcp)
    {
        TcpClient = tcp;
    }
}

public class TcpClientDisconnectedEventArgs : EventArgs
{
    public TcpClient TcpClient { get; set; }

    public TcpClientDisconnectedEventArgs(TcpClient tcp)
    {
        TcpClient = tcp;
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏