使用内存流进行网络仿真

时间:2018-06-07 09:53:33

标签: c# serialization memorystream

我必须使用节点和MemoryStream来模拟网络,我想将对象消息从一个节点发送到另一个节点。

问题是当我想要解释流中的IMessage对象时,我总是会遇到异常。另外,我如何模拟server.AcceptClient

例外:

  

System.Runtime.Serialization.SerializationException:&#34;输入流没有有效的二进制格式。起始内容(以字节为单位)为:05-01-00-00-00-22-50-65-65-72-5F-74-6F -5F-50-65-65 ...&#34; < / p>

代码:

public class Network
{
    public List<Node> Nodes { get; set; }

    public Network()
    {
        Nodes = new List<Node>();
    }

    public MemoryStream GetClientStream(string ip)
    {
        foreach (var item in Nodes)
        {
            if (item.Ip == ip)
            {
                return item.Stream;
            }
        }

        return null;
    }
}


public class Node
{
    public string Ip { get; set; }

    public Client ChordClient { get; set; }

    public MemoryStream Stream { get; set; }

    public Network ChordChain { get; set; }

    public Node(string ip, string peerOne, Network network)
    {
        ChordChain = network;
        Ip = ip;
        Console.WriteLine($"Peer with Port {ip} is listening");
        Task.Run(() => openServer());
    }

    private void openServer()
    {
        try
        {
            Byte[] bytes = new Byte[256];

            Stream = new MemoryStream();
            // Enter the listening loop.
            while (true)
            {
                int i;

                while ((i = Stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    Stream.Position = 0;
                    IMessage msg = NodeTest.DeserializeFromStream(Stream);

                    msg.DoOperate();

                    Stream.Flush();
                }
            }
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: {0}", e);
        }
        finally
        {
            // Stop listening for new clients.
        }
    }

    public void Connect(String ip)
    {
        try
        {
            IMessage msg = new Message();

            MemoryStream stream = ChordChain.GetClientStream(ip);

            NodeTest.SerializeToStream(stream, msg);

            Console.WriteLine("Sent: {0}", "sd");
        }
        catch (ArgumentNullException e)
        {
            Console.WriteLine("ArgumentNullException: {0}", e);
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: {0}", e);
        }
        catch (Exception ex)
        {

        }


    }

}

public class NodeTest
{

    public static MemoryStream SerializeToStream(MemoryStream stream, object o)
    {
        IFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, o);

        return stream;
    }

    public static IMessage DeserializeFromStream(MemoryStream stream)
    {

        stream.Position = 0;
        IFormatter formatter = new BinaryFormatter();
        stream.Seek(0, SeekOrigin.Begin);
        object o = formatter.Deserialize(stream);

        return (IMessage)(o);
    }
}

public class Message : IMessage
{

    public void DoOperate()
    {
        Console.WriteLine("Hello");
        Console.ReadKey();
    }

}

public interface IMessage
{
    void DoOperate();
}

感谢您的帮助,但现在我遇到了问题,我怎么能发送对象的固定大小才能正常工作

public class Node
{
    public string Ip { get; set; }

    public Client ChordClient { get; set; }

    public MemoryStream Stream { get; set; }

    public Network ChordChain {get; set; }

    public Node(string ip, string peerOne, Network network)
    {
        ChordChain = network;
        Ip = ip;
        Console.WriteLine($"Peer with Port {ip} is listening");
        Task.Run(() => openServer());
    }

    private void openServer()
    {
        try
        {
            NamedPipeServerStream server = new NamedPipeServerStream(Ip);
            Byte[] bytes = new Byte[256];
            int i;

            while (true)
            {
                server.WaitForConnection();

                while ((i = server.Read(bytes, 0, bytes.Length)) != 0)
                {

                    //Stream.Position = 0;
                    IMessage msg = NodeTest.DeserializeFromStream(server);

                    msg.DoOperate();
                }

            }

            //MemoryStream reader = new MemoryStream(server);
            //StreamWriter writer = new StreamWriter(server);

            //Byte[] bytes = new Byte[256];

            //Stream = new MemoryStream();
            //// Enter the listening loop.
            //while (true)
            //{
            //    int i;

            //    while ((i = Stream.Read(bytes, 0, bytes.Length)) != 0)
            //    {
            //        //Stream.Position = 0;
            //        IMessage msg = NodeTest.DeserializeFromStream(Stream);

            //        msg.DoOperate();

            //        Stream.Flush();
            //    }               
            //}
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: {0}", e);
        }
        finally
        {
            // Stop listening for new clients.
        }
    }

    public void Connect(String ip)
    {
        try
        {              
            IMessage msg = new Message();


            NamedPipeClientStream client = new NamedPipeClientStream(ip);
            client.Connect();

            NodeTest.SerializeToStream(client, msg);

            Console.WriteLine("Sent: {0}", "sd");

            client.Close();
        }
        catch (ArgumentNullException e)
        {
            Console.WriteLine("ArgumentNullException: {0}", e);
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: {0}", e);
        }
        catch(Exception ex)
        {

        }  
    }

}

public class NodeTest
{

    public static void SerializeToStream(NamedPipeClientStream stream, object o)
    { 
        IFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, o);
    }

    public static IMessage DeserializeFromStream(NamedPipeServerStream   stream)
    {

        //stream.Position = 0;
        IFormatter formatter = new BinaryFormatter();
        //stream.Seek(0, SeekOrigin.Begin);
        object o = formatter.Deserialize(stream);

        return (IMessage)(o);
    }  
}

2 个答案:

答案 0 :(得分:1)

我不确定这有什么问题,但你肯定知道你是否有完整的信息。

如果你发送像这样序列化的消息,那么每一方都很难知道它是否收到了整个消息。解决此问题的方法是对序列化消息进行框架化,例如,您发送:

...
[size][serialized message]
[size][serialized message]
...

所以发送给你(1)序列化到内存(2)获取大小为多少字节(3)写入大小(4)写入多字节

并接收你(1)读取大小(2)准确读取多个字节到内存中(3)反序列化

我先把它排除在外。

答案 1 :(得分:1)

您对MemoryStream的使用不是线程安全的。您无法在一个线程上重新定位和读取流,而另一个线程正在写入该流。要为这种类型的异步通信建模,请使用管道流:

cross apply