【问题标题】:Problem with Socket and Serialization C#套接字和序列化 C# 的问题
【发布时间】:2012-09-06 18:48:48
【问题描述】:

我实现了一个使用 Socket 和线程的客户端和服务器模型

当我只想将一个字符串从客户端传递到服务器时,它可以工作。但我想传递一个对象,它会抛出这个错误: "试图反序列化一个空流"

代码如下:


客户:

ASCIIEncoding asen = new ASCIIEncoding();

MemoryStream memoryStream = new MemoryStream();
BinaryFormatter binaryFormatter = new BinaryFormatter();
Command command = new Command("meuLogin", "minhaSenha");
binaryFormatter.Serialize(memoryStream, command);

stream.Write(memoryStream.ToArray(), 0, memoryStream.ToArray().Length);

服务器:

byte[] message = new byte[4096];
int bytesRead = 0;
bytesRead = clientStream.Read(message, 0, 4096);

MemoryStream memoryStream = new MemoryStream(bytesRead);
BinaryFormatter bf1 = new BinaryFormatter();
memoryStream.Position = 0;

Command command = (Command)bf1.Deserialize(memoryStream); 

另一个问题:我从Client复制了Command类并粘贴到Server进行反序列化。这是正确的吗?

谢谢

【问题讨论】:

  • Command 类是如何定义的?请参阅codeproject.com/KB/cs/objserial.aspx 获取指导。
  • 我同意 Andrey 的观点,WCF 会让你的生活变得轻松
  • 与@Andrey 的另一项协议:WCF 将使您的生活更加轻松。
  • 我会研究这个WCF,谢谢!!

标签: c# serialization sockets


【解决方案1】:

我也推荐 WCF。但是,如果您继续使用套接字,您的协议中缺少的关键元素是 message framing

【讨论】:

  • 我会检查 WCF 和消息框架!谢谢!
【解决方案2】:

您从不使用从流中读取的消息。因此,您正在读取的内存流是空的。

顺便说一句,您为什么要使用这些中间 MemoryStreams?

【讨论】:

  • 我假设使用了MemoryStream,因为该对象已经从clientStream 中读取。 @Alan 需要重新考虑他的协议设计。
  • 好吧,我打算在这一行之后使用:Command command = (Command)bf1.Deserialize(memoryStream);但问题出现在这一行
  • @Alan,你想如何从空流中反序列化一个对象???运行此行时,内存流为空。
  • 服务器有一个更严重的问题,因为没有什么可以区分/检查他的clientStream.Read(..)调用读取1还是2,或者例如2个半对象。
【解决方案3】:

回答您的第二个问题:为了最大程度的可维护性,Command 类应位于客户端和服务器都引用的单独程序集中。

回答您的第一个问题:您正尝试从服务器上的空流反序列化,正如异常告诉您的那样。在从memoryStream 反序列化之前,您需要将从clientStream 读取的字节复制到memoryStream。或者,直接使用clientStream 而不是使用memoryStream;这可能需要重新考虑您的协议。

最后,我完全同意@Andrey:考虑使用 WCF。这比原始套接字要好得多。

【讨论】:

  • 我会看到这个 WCF 谢谢!但我不明白你对第一个问题的意思..客户端将字节发送到服务器,然后服务器读取它。当我在服务器上调试时,字节是 381 或其他东西。如果我不明白你,请给我一些伪代码。谢谢
【解决方案4】:

如果您更改服务器代码以使用不同的 MemoryStream 构造函数,问题就会消失。

MemoryStream memoryStream = new MemoryStream(message, 0, bytesRead);

但是,我同意斯蒂芬和其他人的观点。要么使用 WCF,要么使用消息框架。

【讨论】:

  • 不确定这是否属实。对 Pex 套件进行了尝试,无论使用何种构造函数,Pex 在跟踪时仍然抛出异常。
【解决方案5】:

另一个问题:我从Client复制了Command类并粘贴到Server进行反序列化。这是正确的吗?

没有。您的客户端和服务器的命名空间可能不同,因此服务器将尝试反序列化与其命名空间匹配的流。

您应该使用自己的命名空间创建您的命令类,并从您的客户端和服务器中引用它。

之后……

客户:

static void StreamToServer(TcpClient client, Command obj) {
  using (NetworkStream ns = client.GetStream()) {
    using (MemoryStream ms = new MemoryStream()) {
      BinaryFormatter formatter = new BinaryFormatter();
      formatter.Serialize(ms, obj);
      byte[] buf = ms.ToArray();
      ns.Write(buf, 0, buf.Length);
    }
  }
}

服务器:

static Command ReadStream(TcpListener listener) {
  Command obj = null;
  using (TcpClient client = listener.AcceptTcpClient()) { // waits for data
    using (NetworkStream ns = client.GetStream()) {
      byte[] buf = new byte[client.ReceiveBufferSize];
      int len = ns.Read(buf, 0, buf.Length);
      using (MemoryStream ms = new MemoryStream(buf, 0, len)) {
        BinaryFormatter formatter = new BinaryFormatter();
        obj = formatter.Deserialize(ms) as Command;
      }
    }
  }
  return obj;
}

WCF 或消息框架可能更容易,但我在工作中并不经常有机会坐下来看书。

【讨论】:

    【解决方案6】:

    您应该传递“消息”,而不是将 bytesRead 传递给实际上是字节流长度的 MemoryStream,因为它是实际的字节流。喜欢,

    MemoryStream memoryStream = new MemoryStream(message);
    

    当您传递一个整数变量时,编译器会抛出流为空的异常。

    对于 WCF,它是一个了不起的框架,但是对于需要低延迟和高性能的应用程序,WCF 是一个可怕的答案,因为它的开销,它是建立在套接字上的。因此,如果您使用套接字,那将是最低级别的实现,因此也是最快的。这取决于您的应用程序应该选择哪种范例...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-19
      • 2013-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多