如何使用套接字和无效扩展(Rx)从连接的客户端套接字获取接收的消息缓冲区

时间:2011-07-27 05:27:31

标签: .net sockets c#-4.0 system.reactive reactive-programming

因为我对Rx有点新意并且通过它学习我的方式。我查看了很多例子,但没有一个符合我的需要。

场景:我有一个套接字服务器套接字(使用简单套接字对象而不是TCPListener对象创建)。我有多个客户端(客户端套接字而不是TCPClient)连接到此服务器套接字。我试图使用Rx(反应式扩展)来获取客户端套接字发送的消息,方法是使用“FromAsyncPattern”运算符进行BeginReceive和EndReceive异步操作。

我差点开始在缓冲区中获取消息。但问题是缓冲区返回从先前操作收到的相同消息,或者将具有来自当前和先前接收操作的混合内容。

以下是使用的代码:

    private void ReceiveMessageFromClient(Socket socket)
    {
        try
        {
            if (socket != null)
            {
                byte[] buffer = new byte[400];

                var functionReceiveSocketData = Observable.FromAsyncPattern
                                                            <byte[], int, int, SocketFlags, int>(socket.BeginReceive, socket.EndReceive);

                Observable.Defer(() =>
                                functionReceiveSocketData(buffer, 0, 400, SocketFlags.None)
                                ).Repeat().Subscribe(onNext: x => OnMessageReceived(buffer));
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

OnMessageReceived方法只是一个委托,用于引发消息接收事件并将缓冲区发送到其他类以进一步处理。

问题:使用相同的缓冲区我知道如何从先前收到的缓冲区中清除收到的消息。

- 如果我收到部分消息并且下一条消息实际上是同一消息的一部分,该怎么办。

请帮助我解决上述问题,并提供一些非常棒的代码段。发布此问题的原因是因为我到目前为止所使用的实现都在使用TCPListener,这里的约束是使用套接字对象:(

提前致谢。

1 个答案:

答案 0 :(得分:2)

您遇到的问题是您在重复调用可观察对象之间共享缓冲区的同一实例。您需要确保每次都有一个新的缓冲区实例。您还应该根据返回整数截断缓冲区。以下是我建议您需要进入if声明的内容:

var functionReceiveSocketData =
    Observable.FromAsyncPattern<byte[], int, int, SocketFlags, int>
        (socket.BeginReceive, socket.EndReceive);

Func<byte[], int, byte[]> copy = (bs, n) =>
{
    var rs = new byte[n];
    bs.CopyTo(rs, 0);
    return rs;
};

Observable
    .Defer(() =>
    {
        var buffer = new byte[400];
        return 
            from n in functionReceiveSocketData(buffer, 0, 400, SocketFlags.None)
            select copy(buffer, n);
    })
    .Repeat()
    .Subscribe(x => OnMessageReceived(x));

编辑:回复评论重新加入消息部分。同样修复了上述解决方案 - 在0 lambda的n函数中应该是CopyTo而不是copy

我不是使用套接字的专家,但是,因为套接字是(如果我错了,请纠正我)只是一个字节流,你需要能够确定每条消息的时间在流中已完成。

这是一种可能的方法:

/* include `functionReceiveSocketData` & `copy` from above */ =

Func<byte[], byte[], byte[]> append = (bs1, bs2) =>
{
    var rs = new byte[bs1.Length + bs2.Length];
    bs1.CopyTo(rs, 0);
    bs2.CopyTo(rs, bs1.Length);
    return rs;
};

var messages = new Subject<byte[]>();
messages.Subscribe(x => OnMessageReceived(x));

Observable
    .Defer(() => /* as above */)
    .Repeat()
    .Scan(new byte[] { }, (abs, bs) =>
    {
        var current = append(abs, bs);
        if (isCompleteMessage(current))
        {
            messages.OnNext(current);
            current = new byte[] { };
        }
        return current;
    })
    .Subscribe();

您唯一需要做的就是弄清楚如何实施isCompleteMessage功能。