【问题标题】:Using Binary Formatter with asynchronous sockets将二进制格式化程序与异步套接字一起使用
【发布时间】:2019-05-24 12:15:53
【问题描述】:

我正在尝试通过使用 BinaryFormatter 进行序列化/反序列化来利用 C# 中异步套接字的优势,但遇到了一些问题。主要是,我不断收到错误:

No map for object 1953724755

尝试反序列化网络流时。

我尝试更改为同步套接字,这似乎可以正常工作,但是当使用异步套接字(使用 BeginRecieve 和 EndRecieve 等)时,我仍然会收到此错误。

这是我要反序列化的代码:

private void BeginDictionaryRecieve(IAsyncResult ar)
{
    Stream socketStream = new NetworkStream(socketState.workSocket);
    IFormatter dataFormatter = new BinaryFormatter();
    socketState.workSocket.EndReceive(ar);
    List<string> rackthatWasClicked = (List<string>) 
        dataFormatter.Deserialize(socketStream);
    this.recievedListForRackDisplay = rackthatWasClicked;
    OnDataRecieved.Invoke();
    socketState.workSocket.BeginReceive(socketState.buffer, 0, StateObject.BufferSize, 0,new AsyncCallback(BeginDictionaryRecieve), socketState);
}

这里是序列化代码(同步):

IPAddress ipAdd = IPAddress.Parse("127.0.0.1");
TcpClient myClient = new TcpClient();
myClient.Connect(ipAdd, 8002);
Stream clientStream = myClient.GetStream();
IFormatter f = new BinaryFormatter();
f.Serialize(clientStream, ShelfDataToSend);
clientStream.Dispose();
myClient.Dispose();

我应该注意我正在使用 BinaryFormatter,因为我似乎无法找到一种方法来序列化一个对象,而不是在套接字上使用正常的 .Write 操作来序列化一个对象。

【问题讨论】:

  • 您收到通知说在 socketState.buffer 中收到了字节,但 Deserialize() 没有使用它们。因此,当它试图从丢失的字节中反序列化时,它就会崩溃。考虑使用 MemoryStream 存储接收到的数据,但您必须对其进行构图,以便知道何时收到所有数据。或者使用一个任务,这样你就不需要 BeginReceive,有点浪费,但肯定更容易上手。
  • @HansPassant 如果我使用 MemoryStream,我是否会将所有收到的字节收集到其中,然后尝试反序列化 MemoryStream? BinaryFormatter 是否允许这种操作?我似乎在文档中找不到任何关于它的内容
  • BinaryFormatter.Deserialize 可以采用任何流。但是您必须确保 MemoryStream 包含 BinaryFormatter 所需的准确 字节数,这就是问题所在。使用 TCP 组帧数据是通过首先传输 byte[] 的大小来完成的,以便接收者知道多久调用一次 Receive 来获取所有数据。要知道该大小,您还必须在传输端同样使用 MemoryStream。使用 Task 使其异步会容易得多。
  • @HansPassant 很抱歉,您认为您可以发布一个示例作为答案吗?我在关注时遇到了一些问题
  • 那里有很多例子,google "c# tcp send byte array" 找到它们。

标签: c# sockets asynchronous binaryformatter


【解决方案1】:

在 Hans 的指导下,我找到了一个很好的解决方案。我现在收到这样的数据:

try
{
    StateObject state = (StateObject) ar.AsyncState;
    Socket client = state.workSocket;

    int bytesRead = client.EndReceive(ar);

    if (bytesRead > 0)
    {
        stream.Write(state.buffer, 0, bytesRead);
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(BeginDictionaryRecieve), state);
    }
    else
    {
        if (stream.Length > 1)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            stream.Position = 0;
            this.recievedListForRackDisplay =(List<string>)formatter.Deserialize(stream);
            OnDataRecieved.Invoke();

            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                            new AsyncCallback(BeginDictionaryRecieve), state);
        }
    }

}
catch (Exception e)
{
    throw e;
}

还应注意,此解决方案仅在客户端 Socket 在发送其数据后被处理时才有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-26
    • 2013-09-23
    • 2021-01-19
    • 1970-01-01
    • 2013-07-10
    相关资源
    最近更新 更多