XmlSerializer不会通过NetworkStream反序列化 [英] XmlSerializer Won't Deserialize over NetworkStream

查看:85
本文介绍了XmlSerializer不会通过NetworkStream反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻求实现一个简单的客户端/服务器设置,该设置可以传输序列化的 EmailRequest 对象(使用 XmlSerializer )从客户端到服务器,用于发送电子邮件。

I'm looking to implement a simple Client/Server setup that can transfer a serialized EmailRequest object (using XmlSerializer) from the client to the server, to be used to send an email.

class Program
{
    private static void Main()
    {
        try
        {
            TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8888);

            listener.Start();

            while (true)
            {
                Console.WriteLine("Waiting for request..");

                TcpClient client = listener.AcceptTcpClient();

                NetworkStream stream = client.GetStream();

                XmlSerializer serializer = new XmlSerializer(typeof(EmailRequest));

                EmailRequest request = (EmailRequest)serializer.Deserialize(stream); // This is where the problem is //

                bool success = SendGridUtility.SendEmail(request.Recipients, request.Subject,
                    request.BodyType == EmailRequest.Type.Plain ? request.PlainText : request.HTMLText,
                    request.BodyType).Result;

                byte[] response = Encoding.ASCII.GetBytes(success ? "Success" : "Failure");
                Console.WriteLine("Email Successfully Sent!");

                stream.Write(response, 0, response.Length);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Something went wrong.. :( :\n" + e.Message + "\n\n");
        }
        Console.ReadLine();
    }
}



客户



Client

class Program
{
    static void Main(string[] args)
    {
        try
        {
            TcpClient client = new TcpClient("127.0.0.1", 8888);

            NetworkStream stream = client.GetStream();

            XmlSerializer serializer = new XmlSerializer(typeof(EmailRequest));

            EmailRequest request = new EmailRequest
            {
                BodyType = EmailRequest.Type.Plain,
                HTMLText = "not used",
                PlainText = "Email Body",
                Recipients = new List<string> {"johnsmith@example.com"},
                Subject = "Email Subject"
            };

            serializer.Serialize(stream,request);

            Byte[] data = new Byte[256];

            Int32 bytes = stream.Read(data, 0, data.Length);
            string responseData = Encoding.ASCII.GetString(data, 0, bytes);
            Console.WriteLine("Received: {0}", responseData);
            Console.ReadLine();

        }
        catch (Exception e)
        {
            Console.WriteLine(e.StackTrace + "\n\n");
            Console.WriteLine(e.Message);
            Console.ReadLine();
        }
    }
}



电子邮件请求模型



EmailRequest Model

[Serializable]
public class EmailRequest
{
    public enum Type
    {
        Plain,
        HTML
    }
    public List<string> Recipients { get; set; }
    public string Subject { get; set; }
    public Type BodyType { get; set; }
    public string PlainText { get; set; }
    public string HTMLText { get; set; }
}

程序到达反序列化方法,该应用程序不会挂起,但会等待,好像在等待用户输入一样,我也不知道为什么。除了我今天所做的以外,我还没有TCP / XmlSerialization / Streams的经验。与往常一样,有关如何改进程序的任何帮助或建议将不胜感激。谢谢。

When the program reaches the Deserialize method, the application doesn't hang, but waits, as though it's expecting user-input, and I have no idea why. I've got no experience with TCP/XmlSerialization/Streams apart from what I've done today. Any help or suggestions as to how I could improve the program would, as always, be much appreciated. Thanks.

推荐答案

这里的问题是 XmlSerializer 无法知道没有更多的数据要反序列化,因为客户端无法关闭套接字。

The problem here is that the XmlSerializer has no way to know that there is no more data to deserialize, because the client has failed to shutdown the socket.

在调用 serializer.Serialize(流,请求); ,则需要添加以下代码行:

After the call to serializer.Serialize(stream,request);, you will need to add this line of code:

client.Client.Shutdown(SocketShutdown.Send);

这将指示客户端的流结束,以便服务器知道数据传输已完成。这使 XmlSerializer 知道没有更多尝试反序列化的方法,并且可以返回新对象。

This will indicate the end-of-stream from the client side, so that the server knows that the transmission of data has completed. This allows the XmlSerializer to know there's nothing more to try to deserialize and that it can return the new object.

此外,服务器也不会调用 Shutdown()。您可以通过发布的代码来解决它,因为您的客户端在接收时不会检查流的结尾。

In addition, the server never calls Shutdown() either. You can get away with it with the code you posted, because your client doesn't check for the end-of-stream when receiving.

虽然这几乎可以正常工作一直以来,这都不是正确的。由于您不检查接收值的长度,因此您无法知道客户端已收到服务器已发送的所有数据作为响应。

While that will probably work nearly all of the time, it's not quite correct. Since you don't check the length of the receive value, you have no way to know that the client has received all of the data that the server has sent in response.

相反,您应该首先修复服务器以调用 Shutdown(),方法是在将响应写入流之后添加以下语句:

Instead, you should first fix the server to call Shutdown(), by adding these statements after you write the response to the stream:

client.Client.Shutdown(SocketShutdown.Both);
client.Close();

然后,您还需要修复客户端…

Then, you also need to fix the client side…

客户端处理响应的一种更简单,更可靠的方法是用以下命令替换对 Shutdown()的所有调用:

A simpler and more reliable way for the client to deal with processing the response would be to replace everything after the call to Shutdown() with this:

using (StreamReader reader = new StreamReader(stream))
{
    string line;

    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine("Received: " + line);
    }
}

这使您不必担心基础流I / O直接,而不是将其委托给 StreamReader 类,该类可以以更方便的方式处理数据(即,它自动缓冲数据并正确检测流的结束)。

This allows you to not worry about the underlying stream I/O directly, instead delegating that to the StreamReader class, which can process the data in a more convenient way (i.e. it automatically buffers the data and correct detects the end of the stream).

最后,在收到剩余数据(按上述方法)之后,您还应该关闭客户端套接字:

Finally, after receiving the remaining data (per above), you should also close the client socket:

client.Close();

这篇关于XmlSerializer不会通过NetworkStream反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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