C#为什么不"同花顺"压低网络流字节? [英] C# Why doesn't "Flush" force the bytes down the network stream?

查看:127
本文介绍了C#为什么不"同花顺"压低网络流字节?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个项目,我想序列化对象发送到服务器,然后等待一个OK或错误消息回来了。

I have a project where I'm trying to send a serialized object to the server, then wait for an "OK" or "ERROR" message to come back.

我似乎有类似的问题,以钍海报: TcpClient的发送/关闭问题

I seem to be having a similar problem to th poster of : TcpClient send/close problem

的问题是,我似乎只有这样,才能能够发送原始对象是关闭连接,但(当然)我不能等待看看如果对象是由服务器成功处理。

The issue is that the only way I seem to be able to send the original object is to close the connection, but then (of course) I can't wait to see if the object was processed successfully by the server.

private void button4_Click(object sender, EventArgs e)
{
    RequestPacket req = new RequestPacket();

    /// ... Fill out request packet ...

    /// Connect to the SERVER to send the message...
    TcpClient Client = new TcpClient("localhost", 10287);
    using (NetworkStream ns = Client.GetStream())
    {
        XmlSerializer xml = new XmlSerializer(typeof(RequestPacket));
        xml.Serialize(ns, req);

        /// NOTE: This doesn't seem to do anything.... 
        ///       The server doesn't get the object I just serialized.
        ///       However, if I use ns.Close() it does... 
        ///          but then I can't get the response.
        ns.Flush();

        // Get the response. It should be "OK".
        ResponsePacket resp;

        XmlSerializer xml2 = new XmlSerializer(typeof(ResponsePacket));
        resp = (ResponsePacket)xml2.Deserialize(ns);


        /// ... EVALUATE RESPONSE ...
    }

    Client.Close()
}

更新:在回答一位评论者,我不认为客户端可以在故障。它只是在等待的对象,该对象还没有出现,直到我关闭套接字....但是,如果我错了,我会很乐意吃乌鸦公开。 =)这里的客户端:

UPDATE: In response to one commenter, I don't think the client can be at fault. It is simply waiting for the object, and the object never comes until I close the socket.... however, if I'm wrong, I'll GLADLY eat crow publicly. =) Here's the client:

    static void Main(string[] args)
    {
        // Read the port from the command line, use 10287 for default
        CMD cmd = new CMD(args);
        int port = 10287;

        if (cmd.ContainsKey("p")) port = Convert.ToInt32(cmd["p"]);

        TcpListener l = new TcpListener(port);
        l.Start();

        while (true)
        {
            // Wait for a socket connection.
            TcpClient c = l.AcceptTcpClient();

            Thread T = new Thread(ProcessSocket);

            T.Start(c);
        }
    }


    static void ProcessSocket(object c)
    {
        TcpClient C = (TcpClient)c;

        try
        {
            RequestPacket rp;
            //// Handle the request here.
            using (NetworkStream ns = C.GetStream())
            {
                XmlSerializer xml = new XmlSerializer(typeof(RequestPacket));
                rp = (RequestPacket)xml.Deserialize(ns);
            }

            ProcessPacket(rp);
        }
        catch
        {
            // not much to do except ignore it and go on.
        }
    }



啊....就这么简单。

Yeah.... it's that simple.

推荐答案

短的版本显然,使用XmlSerializer的(或任何其他大的blob),以推数据下来的NetworkStream的时候,它会简单地举行开行无限期地等待写入更多的信息。它仅仅刷新,一旦你关闭连接。这将创建一种情况,这种方法是伟大的发送,但没有收到。或相反亦然。它变成了单向通信,没用超过同一连接继续回来,来回沟通。

The short version is apparently, when using XmlSerializer (or any other big blob) to shove data down a NetworkStream, it will simply hold the line open indefinitely waiting for more information to be written. It only flushes the connection once you close it. This creates a situation where this method is great for sending, but not receiving. Or vice-versa. It becomes a one-way communication, and useless for continued back-and-forth communication over the same connection.

这是一种糟糕,我不得不解决的东西,似乎在表面上那么优雅,但下探回到我的旧的C日子里,我已经使出了第一个发送数据包的字节数,那么实际的数据包。这使我在另一端要读取的字节的确切数字,所以我从来没有在阻塞模式被逮住。

It's kind of crappy that I had to work around something that seemed so elegant on the surface, but dropping back to my old C days, I've resorted to sending a "number of bytes" packet first, then the actual packet. This enables me to READ at the other end the exact number of bytes so I never get caught in a blocking pattern.

要简化我的生活,我创建了持有类一些静态方法来发送和接收。这个类可以发送任何XML序列化的类在网络上,所以它做什么,我需要做的。

To simplify my life, I created a class that holds some static methods for both sending and receiving. This class can send ANY XML-serializable class across the network, so it does what I need it to do.

如果任何人有一个更好的解决方案,我会开听到它。

If anyone has a more elegant solution, I'd be open to hearing it.

public class PacketTransit
{
    public static void SendPacket(TcpClient C, object Packet)
    {
        MemoryStream ms = new MemoryStream();
        XmlSerializer xml = new XmlSerializer(Packet.GetType());
        xml.Serialize(ms, Packet);
        ms.Position = 0;
        byte[] b = ms.GetBuffer();
        ms.Dispose();

        byte [] sizePacket = BitConverter.GetBytes(b.Length);
        // Send the 4-byte size packet first.
        C.Client.Send(sizePacket, sizePacket.Length, SocketFlags.None);
        C.Client.Send(b, b.Length, SocketFlags.None);
    }

    /// The string is the XML file that needs to be converted.
    public static string ReceivePacket(TcpClient C, Type PacketType)
    {
        byte [] FirstTen = new byte[1024];
        int size = 0;
        byte[] sizePacket = BitConverter.GetBytes(size);

        // Get the size packet
        int sp = C.Client.Receive(sizePacket, sizePacket.Length, SocketFlags.None);
        if (sp <= 0) return "";

        size = BitConverter.ToInt32(sizePacket, 0);

        // read until "size" is met
        StringBuilder sb = new StringBuilder();
        while (size > 0)
        {
            byte[] b = new byte[1024];
            int x = size;
            if (x > 1024) x = 1024;
            int r = C.Client.Receive(b, x, SocketFlags.None);
            size -= r;
            sb.Append(UTF8Encoding.UTF8.GetString(b));
        }

        return sb.ToString();
    }

    /// The XML data that needs to be converted back to the appropriate type.
    public static object Decode(string PacketData, Type PacketType)
    {
        MemoryStream ms = new MemoryStream(UTF8Encoding.UTF8.GetBytes(PacketData));
        XmlSerializer xml = new XmlSerializer(PacketType);
        object obj = xml.Deserialize(ms);
        ms.Dispose();

        return obj;
    }

    public static RequestPacket GetRequestPacket(TcpClient C)
    {
        string str = ReceivePacket(C, typeof(RequestPacket));

        if (str == "") return new RequestPacket();

        RequestPacket req = (RequestPacket) Decode(str, typeof(RequestPacket));

        return req;
    }

    public static ResponsePacket GetResponsePacket(TcpClient C)
    {
        string str = ReceivePacket(C, typeof(ResponsePacket));

        if (str == "") return new ResponsePacket();

        ResponsePacket res = (ResponsePacket)Decode(str, typeof(ResponsePacket));

        return res;
    }
}

要使用这个类,我只需要调用 PacketTransit.SendPacket(myTcpClient,SomePacket)发送任何给定的XML序列化对象。然后我可以使用 PacketTransit.GetResponsePacket PacketTransit.GetRequestPacket 在另一端接收它。

To use this class, I simply need to call PacketTransit.SendPacket(myTcpClient, SomePacket) to send any given XML-Serializable object. I can then use PacketTransit.GetResponsePacket or PacketTransit.GetRequestPacket to receive it at the other end.

对于我来说,这是工作得非常好,但它是很多更比原先预期的锻炼。

For me, this is working very well, but it was alot more of a workout than originally expected.

这篇关于C#为什么不&QUOT;同花顺&QUOT;压低网络流字节?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆