首页 > 解决方案 > 在 C# 中使用 BinaryFormatter 转换从 C 服务器发送的数据

问题描述

我正在尝试使用 C 和 C# 进行通信。这是从 C++ 服务器发送结构的代码,客户端接收、解释并发送回 C 服务器。

我尝试在将其作为注释关闭的代码部分中使用 BinaryFormatter 转换为 int 类型,但出现异常。

异常:未处理的异常:System.Runtime.Serialization.SerializationException:在解析完成之前到达流的结尾。

所以我被迫使用BitConverter,但BitConverter只能转换为固定类型。

如果这不起作用,我将无法发送和接收结构。这个问题有解决方案吗?

[C服务器]

#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32")

#define PORT 4567

void err_exit(const char* msg) {
    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        0, WSAGetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPSTR)&lpMsgBuf, 0, 0);
    MessageBox(NULL, (LPCSTR)lpMsgBuf, msg, MB_OK);
    LocalFree(lpMsgBuf);
    exit(1);
}

int recvn(SOCKET sock, char* buffer, int length, int flags) {
    int curLen = 0;
    while (curLen < length) {
        int recvLen = recv(sock, buffer, length, flags);
        if (recvLen < 1)
            return SOCKET_ERROR;
        buffer += recvLen;
        curLen += recvLen;
    }
    return curLen;
}

int main(int argc, char* argv[]) {
    printf("c server\n");

    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);

    SOCKET gate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (gate == INVALID_SOCKET)err_exit("gate");
    SOCKADDR_IN gateAddress = { 0, };
    gateAddress.sin_family = AF_INET;
    gateAddress.sin_addr.s_addr = htonl(INADDR_ANY);
    gateAddress.sin_port = htons(PORT);
    if (bind(gate, (const sockaddr*)&gateAddress, sizeof(gateAddress)) == SOCKET_ERROR)err_exit("bind");
    if (listen(gate, SOMAXCONN) == SOCKET_ERROR)err_exit("listen");
    SOCKADDR_IN clientAddress = { 0, };
    int cliAddrSize = sizeof(clientAddress);
    SOCKET client = accept(gate, (sockaddr*)&clientAddress, &cliAddrSize);

    int sendNum = 99999;
    int sendLen = send(client, (char*)&sendNum, sizeof(int), 0);
    printf("send: %d\n", sendNum);
    int recvNum = 0;
    int recvLen = recvn(client, (char*)&recvNum, sizeof(int), 0);
    printf("recv: %d\n", recvNum);

    closesocket(client);
    closesocket(gate);
    WSACleanup();
    system("pause");
}

[C#客户端]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.InteropServices;
using System.Net;
using System.Net.Sockets;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("C# client");

            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
            sock.Connect(iPEndPoint);

            int recvNum = 0;
            byte[] recvBuf = new byte[sizeof(int)];
            sock.Receive(recvBuf);
            recvNum = BitConverter.ToInt32(recvBuf, 0);
            Console.WriteLine("recv: " + recvNum);

            // Here is error.
            // Unhandled Exception: 
            // System.Runtime.Serialization.SerializationException: 
            // End of stream reached before parsing completed.
            /* 
            using (MemoryStream ms = new MemoryStream(recvBuf))
            {
                BinaryFormatter bf = new BinaryFormatter();
                recvNum = (int)bf.Deserialize(ms);
            }
            //*/

            sock.Send(recvBuf);
            Console.WriteLine("send: " + recvNum);

            sock.Close();
        }
    }
}

我只是在 C# 中使用 BinaryFormatter 将它转换为字节数组。这就是结果。

int 到字节数组 -> 159,134,1,0,

使用 BinaryFormatter 将 int 转换为字节数组 -> 0,1,0,0,0,255,255,255,255,1,0,0,0,0,0,0,0,4,1,0,0,0,12,83,121,115,116,101,109,46 ,73,110,116,51,50,1,0,0,0,7,109,95,118,97,108,117,101,0,8, 159,134,1,0 ,11,

BinaryFormatter 似乎在字节的开头和数据的结尾存储了不同的信息。

我应该使用 BinaryFormatter 以外的东西吗?

标签: c#socketsbinaryformatter

解决方案


BinaryFormatter 序列化“对象图”,它是具有类型信息的数据。

BinaryReader是您可能正在寻找的类。


推荐阅读