首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >System.Net.Sockets的发送/接收包装器

System.Net.Sockets的发送/接收包装器
EN

Code Review用户
提问于 2019-06-25 19:37:24
回答 1查看 308关注 0票数 6

下面的NetworkEndpoint类作为网络连接(客户端或服务器)任何一方的一个简单的发送/接收接口,只要提供一个套接字即可操作。

对于当前状态下的代码,我有两个主要的担忧:

  1. 我能做些什么来改进异常处理,以便更好地处理套接字断开(意外地和有意地)?
  2. 据我所知,我已经保护多个接收循环开始启动。(if (Receiving) return; in void InitializeReceiveLoop())但是还有其他一些我忽略的线程安全问题吗??

我对C#的知识主要是自学的,所以如果我的代码没有反映最佳实践或标准样式指南,我很抱歉。

任何有关这些问题的建议或关于改进我的代码的一般性建议都将不胜感激。

代码语言:javascript
复制
public class NetworkEndpoint {

    private Socket connection;
    public bool Connected { get => connection != null ? connection.Connected : false; }
    public bool Receiving { get; private set; }

    public event EventHandler<NetworkReceiveEventArgs> DataReceived;
    private void OnDataReceived(NetworkHeader header, byte[] data) =>
    DataReceived?.Invoke(this, new NetworkReceiveEventArgs(header, data));

    public event EventHandler Disconnected;
    private void OnDisconnected() =>
    Disconnected?.Invoke(this, new EventArgs());

    public NetworkEndpoint(Socket socket) {
        connection = socket ?? throw new ArgumentNullException("socket");
        Receiving = false;
    }

    public void Send(NetworkHeader header, byte[] data) {
        if (!Connected) throw new InvalidOperationException("NetworkEndpoint must be connected before sending.");
        try {
            connection.Send(ByteUtils.Combine(header.Serialize(), data));
            } catch (SocketException ex) {
            Disconnect();
        }

    }

    public void Disconnect() {
        connection?.Shutdown(SocketShutdown.Both);
        connection?.Close();
        connection = null;
        OnDisconnected();
    }

    public void InitializeReceiveLoop() {
        if (Receiving) return;

        Receiving = true;
        BeginReceive();
    }

    private byte[] headBuffer = new byte[NetworkHeader.ByteSize];
    private void BeginReceive() {
        connection.BeginReceive(headBuffer, 0, NetworkHeader.ByteSize, SocketFlags.None, EndReceive, null);
    }

    private void EndReceive(IAsyncResult result) {
        bool fullyReceived = false;
        byte[] dataBuffer = null;
        NetworkHeader header = null;

        try {
            if (connection.EndReceive(result) > 0) {
                header = NetworkHeader.Deserialize(headBuffer);
                dataBuffer = new byte[header.DataSize];

                int receivedLength = connection.Receive(dataBuffer, 0, dataBuffer.Length, SocketFlags.None);
                fullyReceived = (receivedLength == header.DataSize);
            }
        } catch (SocketException) { }

        if (fullyReceived) {
            OnDataReceived(header, dataBuffer);
            BeginReceive();
        } else if (connection.Connected) Disconnect();
    }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2019-06-26 06:32:45

评论

  • 属性Connected不是线程安全的.使用Interlocked.CompareExchange以原子方式获取连接。
  • 事件DataReceivedDisconnected从未被清除。这会导致内存泄漏。实现Clear函数和/或实现IDisposable
  • 方法SendDisconnectEndReceive不线程安全.考虑使用互斥锁。
  • fullyReceived上检查receivedLength == header.DataSize是很天真的,可能会被破坏。TCP消息可以在几个数据包中发送。使用内部缓冲区代替。此外,receivedLength = 0是确定没有更多数据可用的一种干净方法。
  • 盲目地捕捉SocketException是一种代码气味.
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/222944

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档