Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用无功扩展(Rx)进行套接字编程是否可行?_C#_.net_Sockets_System.reactive - Fatal编程技术网

C# 使用无功扩展(Rx)进行套接字编程是否可行?

C# 使用无功扩展(Rx)进行套接字编程是否可行?,c#,.net,sockets,system.reactive,C#,.net,Sockets,System.reactive,使用Rx编写GetMessages函数最简洁的方法是什么: static void Main() { Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var messages = GetMessages(socket, IPAddress.Loopback, 4000); messages.Subscribe(x => Cons

使用Rx编写
GetMessages
函数最简洁的方法是什么:

static void Main()
{
    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    var messages = GetMessages(socket, IPAddress.Loopback, 4000);
    messages.Subscribe(x => Console.WriteLine(x));

    Console.ReadKey();
}

static IObservable<string> GetMessages(Socket socket, IPAddress addr, int port)
{
    var whenConnect = Observable.FromAsyncPattern<IPAddress, int>(socket.BeginConnect, socket.EndConnect)(addr, port);

    // now will receive a stream of messages
    // each message is prefixed with an 4 bytes/Int32 indicating it's length. 
    // the rest of the message is a string

    // ????????????? Now What ????????????? 
}
好吧,这可能是“作弊”,但我想你可以重新确定我的非Rx答案的用途,并用
Observable.Create
将其包装起来

我相当确定将套接字返回为
IDisposable
是错误的语义,但不确定会是什么

    static IObservable<string> GetMessages(Socket socket, IPAddress addr, int port)
    {
        return Observable.CreateWithDisposable<string>(
            o =>
            {
                byte[] buffer = new byte[1024];

                Action<int, Action<int>> readIntoBuffer = (length, callback) =>
                {
                    var totalRead = 0;

                    AsyncCallback receiveCallback = null;
                    AsyncCallback temp = r =>
                    {
                        var read = socket.EndReceive(r);

                        if (read == 0)
                        {
                            socket.Close();
                            o.OnCompleted();
                            return;
                        }

                        totalRead += read;

                        if (totalRead < length)
                        {
                            socket.BeginReceive(buffer, totalRead, length - totalRead, SocketFlags.None, receiveCallback, null);
                        }
                        else
                        {
                            callback(length);
                        }
                    };
                    receiveCallback = temp;

                    socket.BeginReceive(buffer, totalRead, length, SocketFlags.None, receiveCallback, null);
                };

                Action<int> sizeRead = null;

                Action<int> messageRead = x =>
                {
                    var message = Encoding.UTF8.GetString(buffer, 0, x);
                    o.OnNext(message);
                    readIntoBuffer(4, sizeRead);
                };

                Action<int> temp2 = x =>
                {
                    var size = BitConverter.ToInt32(buffer, 0);
                    readIntoBuffer(size, messageRead);
                };
                sizeRead = temp2;

                AsyncCallback connectCallback = r =>
                {
                    socket.EndConnect(r);
                    readIntoBuffer(4, sizeRead);
                };

                socket.BeginConnect(addr, port, connectCallback, null);

                return socket;
            });
    }
static IObservable GetMessages(套接字、IPAddress addr、int端口)
{
返回可观察的.CreateWithDisposable(
o=>
{
字节[]缓冲区=新字节[1024];
操作readIntoBuffer=(长度,回调)=>
{
var totalRead=0;
AsyncCallback-receiveCallback=null;
异步回调温度=r=>
{
var read=socket.EndReceive(r);
如果(读==0)
{
socket.Close();
o、 未完成();
返回;
}
totalRead+=读取;
if(总读取<长度)
{
socket.BeginReceive(缓冲区、totalRead、长度-totalRead、SocketFlags.None、receiveCallback、null);
}
其他的
{
回调(长度);
}
};
receiveCallback=temp;
socket.BeginReceive(缓冲区、totalRead、长度、SocketFlags.None、receiveCallback、null);
};
Action sizeRead=null;
Action messageRead=x=>
{
var message=Encoding.UTF8.GetString(缓冲区,0,x);
o、 OnNext(消息);
readIntoBuffer(4,sizeRead);
};
动作节奏2=x=>
{
变量大小=位转换器.ToInt32(缓冲区,0);
readIntoBuffer(大小,messageRead);
};
sizeRead=temp2;
AsyncCallback-connectCallback=r=>
{
插座.端接(r);
readIntoBuffer(4,sizeRead);
};
BeginConnect(addr,port,connectCallback,null);
返回插座;
});
}

按照这些思路做的事情可能会奏效。这没有经过测试,不考虑异常和部分返回消息的情况。但除此之外,我相信这是一个正确的方向

    public static IObservable<T> GetSocketData<T>(this Socket socket,
        int sizeToRead, Func<byte[], T> valueExtractor)
    {
        return Observable.CreateWithDisposable<T>(observer =>
        {
            var readSize = Observable
                .FromAsyncPattern<byte[], int, int, SocketFlags, int>(
                socket.BeginReceive,
                socket.EndReceive);
            var buffer = new byte[sizeToRead];
            return readSize(buffer, 0, sizeToRead, SocketFlags.None)
                .Subscribe(
                x => observer.OnNext(valueExtractor(buffer)),
                    observer.OnError,
                    observer.OnCompleted);
        });
    }

    public static IObservable<int> GetMessageSize(this Socket socket)
    {
        return socket.GetSocketData(4, buf => BitConverter.ToInt32(buf, 0));
    }

    public static IObservable<string> GetMessageBody(this Socket socket,
        int messageSize)
    {
        return socket.GetSocketData(messageSize, buf =>
            Encoding.UTF8.GetString(buf, 0, messageSize));
    }

    public static IObservable<string> GetMessage(this Socket socket)
    {

        return
            from size in socket.GetMessageSize()
            from message in Observable.If(() => size != 0,
                socket.GetMessageBody(size),
                Observable.Return<string>(null))
            select message;
    }

    public static IObservable<string> GetMessagesFromConnected(
        this Socket socket)
    {
        return socket
            .GetMessage()
            .Repeat()
            .TakeWhile(msg => !string.IsNullOrEmpty(msg));
    }

    public static IObservable<string> GetMessages(this Socket socket,
        IPAddress addr, int port)
    {
        return Observable.Defer(() => 
        {
            var whenConnect = Observable
                .FromAsyncPattern<IPAddress, int>(
                    socket.BeginConnect, socket.EndConnect);
            return from _ in whenConnect(addr, port)
                   from msg in socket.GetMessagesFromConnected()
                       .Finally(socket.Close)
                   select msg;
        });
    }
public static IObservable GetSocketData(此套接字,
int-sizeToRead,Func-valueExtractor)
{
返回Observable.CreateWithDisposable(观察者=>
{
var readSize=可观测
.FromAsyncPattern(
socket.BeginReceive,
插座(接收端);
var buffer=新字节[sizeToRead];
返回readSize(缓冲区、0、sizeToRead、SocketFlags.None)
.订阅(
x=>observer.OnNext(值提取器(缓冲区)),
observer.OnError,
观察员(未完成);
});
}
公共静态IObservable GetMessageSize(此套接字)
{
返回socket.GetSocketData(4,buf=>BitConverter.ToInt32(buf,0));
}
公共静态IObservable GetMessageBody(此套接字,
int messageSize)
{
返回socket.GetSocketData(messageSize,buf=>
Encoding.UTF8.GetString(buf,0,messageSize));
}
公共静态IObservable GetMessage(此套接字)
{
返回
来自socket.GetMessageSize()中的大小
如果(()=>大小!=0,
socket.GetMessageBody(大小),
可观察。返回(空)
选择消息;
}
公共静态IObservable GetMessagesFromConnected(
这个插座)
{
返回插座
.GetMessage()
.重复
.TakeWhile(msg=>!string.IsNullOrEmpty(msg));
}
公共静态IObservable GetMessages(此套接字,
IP地址地址(int端口)
{
返回可观察的延迟(()=>
{
var whenConnect=可观测
.FromAsyncPattern(
socket.BeginConnect、socket.EndConnect);
连接时从uu u;返回(地址,端口)
来自socket.GetMessagesFromConnected()中的消息
.Finally(socket.Close)
选择味精;
});
}
编辑:如Dave Sexton在中所建议的,可以使用(在GetSockedData中)来处理不完整的读取


编辑:另外,看看杰弗里·梵高的这篇文章:

我正在做类似的事情。单个“socket”不能直接转换为
IObservable
,因此我正在探索TPL和Rx的混合。例如,连接操作更像是一项任务,而重复读取可以被视为
IO
。如果最终结果足够简单,它将成为其中的一部分。我的想法是,您可以在流的开头使用Connect,然后在流的结尾使用Close,这在某种程度上相当于在生成一些现有Rx示例时使用的MouseDown&MouseUp IObservable事件。当问到这个问题时,它可能不存在,但现在它确实存在,并且可能在这里引起兴趣:“Rxx提供了几个API,使异步调用web请求变得容易,包括(…)System.Net.Sockets.Socket、System.Net.Sockets.TcpClient”。是的,这实际上不起作用,因为EndRecieve返回的值可能小于完整大小,需要另一个请求
    public static IObservable<T> GetSocketData<T>(this Socket socket,
        int sizeToRead, Func<byte[], T> valueExtractor)
    {
        return Observable.CreateWithDisposable<T>(observer =>
        {
            var readSize = Observable
                .FromAsyncPattern<byte[], int, int, SocketFlags, int>(
                socket.BeginReceive,
                socket.EndReceive);
            var buffer = new byte[sizeToRead];
            return readSize(buffer, 0, sizeToRead, SocketFlags.None)
                .Subscribe(
                x => observer.OnNext(valueExtractor(buffer)),
                    observer.OnError,
                    observer.OnCompleted);
        });
    }

    public static IObservable<int> GetMessageSize(this Socket socket)
    {
        return socket.GetSocketData(4, buf => BitConverter.ToInt32(buf, 0));
    }

    public static IObservable<string> GetMessageBody(this Socket socket,
        int messageSize)
    {
        return socket.GetSocketData(messageSize, buf =>
            Encoding.UTF8.GetString(buf, 0, messageSize));
    }

    public static IObservable<string> GetMessage(this Socket socket)
    {

        return
            from size in socket.GetMessageSize()
            from message in Observable.If(() => size != 0,
                socket.GetMessageBody(size),
                Observable.Return<string>(null))
            select message;
    }

    public static IObservable<string> GetMessagesFromConnected(
        this Socket socket)
    {
        return socket
            .GetMessage()
            .Repeat()
            .TakeWhile(msg => !string.IsNullOrEmpty(msg));
    }

    public static IObservable<string> GetMessages(this Socket socket,
        IPAddress addr, int port)
    {
        return Observable.Defer(() => 
        {
            var whenConnect = Observable
                .FromAsyncPattern<IPAddress, int>(
                    socket.BeginConnect, socket.EndConnect);
            return from _ in whenConnect(addr, port)
                   from msg in socket.GetMessagesFromConnected()
                       .Finally(socket.Close)
                   select msg;
        });
    }