You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Socket可否实现类似串口DataReceived的数据接收触发事件

C# Socket 实现自动触发数据接收事件的方案

可以实现,Socket本身没有内置类似串口的DataReceived事件,但我们可以通过封装异步接收逻辑+自定义事件的方式完全复刻串口组件的使用体验。

实现步骤

1. 定义自定义事件参数类

用来传递接收到的数据、远端地址等信息,和串口的SerialDataReceivedEventArgs作用一致:

public class SocketDataReceivedEventArgs : EventArgs
{
    /// <summary>
    /// 本次接收到的字节数据
    /// </summary>
    public byte[] ReceivedData { get; }
    /// <summary>
    /// 发送数据的远端节点地址
    /// </summary>
    public EndPoint RemoteEndPoint { get; }

    public SocketDataReceivedEventArgs(byte[] data, EndPoint remoteEndPoint)
    {
        ReceivedData = data;
        RemoteEndPoint = remoteEndPoint;
    }
}

2. 封装Socket监听类,内置异步接收和事件触发逻辑

public class SocketListenerWrapper
{
    private readonly Socket _socket;
    private readonly byte[] _receiveBuffer;
    /// <summary>
    /// 数据接收事件,有新数据到达时自动触发
    /// </summary>
    public event EventHandler<SocketDataReceivedEventArgs> DataReceived;

    /// <summary>
    /// 构造函数,传入已经完成连接的Socket实例
    /// </summary>
    /// <param name="socket">已连接的Socket</param>
    /// <param name="bufferSize">接收缓冲区大小,默认1024字节</param>
    public SocketListenerWrapper(Socket socket, int bufferSize = 1024)
    {
        _socket = socket ?? throw new ArgumentNullException(nameof(socket));
        _receiveBuffer = new byte[bufferSize];
        // 自动启动异步监听
        StartAsyncReceive();
    }

    private void StartAsyncReceive()
    {
        // 启动异步接收,不会阻塞主线程
        _socket.BeginReceive(
            buffer: _receiveBuffer,
            offset: 0,
            size: _receiveBuffer.Length,
            socketFlags: SocketFlags.None,
            callback: ReceiveAsyncCallback,
            state: null);
    }

    private void ReceiveAsyncCallback(IAsyncResult ar)
    {
        try
        {
            int receivedLength = _socket.EndReceive(ar);
            if (receivedLength <= 0)
            {
                // 对端主动断开连接,可自行扩展断开事件通知
                return;
            }

            // 拷贝本次接收到的有效数据
            byte[] validData = new byte[receivedLength];
            Array.Copy(_receiveBuffer, validData, receivedLength);

            // 触发数据接收事件
            OnDataReceived(new SocketDataReceivedEventArgs(validData, _socket.RemoteEndPoint));

            // 重启下一次异步接收,实现持续监听
            StartAsyncReceive();
        }
        catch (SocketException)
        {
            // 连接异常断开,可自行扩展异常事件通知
        }
    }

    protected virtual void OnDataReceived(SocketDataReceivedEventArgs e)
    {
        DataReceived?.Invoke(this, e);
    }
}

3. 调用方式(和串口组件用法完全一致)

// 示例:先创建并连接Socket
var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect("127.0.0.1", 8888);

// 实例化封装类
var socketWrapper = new SocketListenerWrapper(clientSocket);
// 订阅数据接收事件
socketWrapper.DataReceived += SocketWrapper_DataReceived;

// 事件处理方法,有新数据时自动执行
private void SocketWrapper_DataReceived(object sender, SocketDataReceivedEventArgs e)
{
    string content = Encoding.UTF8.GetString(e.ReceivedData);
    Console.WriteLine($"收到来自[{e.RemoteEndPoint}]的数据:{content}");
}

注意事项

  • 事件默认在Socket异步回调的线程触发,和串口DataReceived行为一致,如果是在WinForm/WPF等UI程序中操作界面控件,需要主动调度到UI线程执行。
  • 可以根据业务需求在封装类中补充粘包拆包、异常通知、主动关闭连接等扩展逻辑。
  • UDP场景下也可以用相同的思路封装BeginReceiveFrom异步回调逻辑,实现UDP数据接收的自动事件通知。

内容的提问来源于stack exchange,提问作者Andys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 15:45:03