当服务器以c结构发送数据时,我们可以在客户端上将缓冲区转换为C++结构吗?

kad*_*ina 6 c c++ sockets linux

我有服务器,用C编写的客户端进程名为NetworkServer.c和NetworkClient.c,这两个正在使用linux套接字进行通信.当客户端发送如下请求以获取以太网统计信息时,

// rxbuf - character array of 128K
// ETHERNET_DIAGNOSTIC_INFO - structure typedefed
recv(sockfd, rxbuf, sizeof(ETHERNET_DIAGNOSTIC_INFO), 0)
Run Code Online (Sandbox Code Playgroud)

服务器将数据填入rxbuf(作为ETHERNET_DIAGNOSTIC_INFO,因为服务器也使用与此结构定义相同的头文件副本)并发送数据.客户端收到后,将按如下方式进行类型转换以获取数据.

ETHERNET_DIAGNOSTIC_INFO *info = (ETHERNET_DIAGNOSTIC_INFO *) rxbuf;
Run Code Online (Sandbox Code Playgroud)

结构在NetworkDiag.h中定义如下.

#ifdef __cplusplus
extern "C" {
#endif

typedef struct ETHERNET_DIAGNOSTIC_INFO
{
    uint32_t             cmdId; 
    unsigned long        RxCount[MAX_SAMPLES];
    unsigned long        TxCount[MAX_SAMPLES];
    time_t               TimeStamp[MAX_SAMPLES] ;
    char                 LanIpAddress[20];
    char                 LanMacAddress[20];
    char                 WanIpAddress[20];
    char                 LanDefaultGateway[20];
    char                 LanSubnetMask[20];
    char                 LanLease[5000];
}ETHERNET_DIAGNOSTIC_INFO;
Run Code Online (Sandbox Code Playgroud)

这工作正常.

现在要求我需要创建一个应该作为客户端工作的c ++文件(我删除了客户端C文件,服务器应该保留为c文件).我为结构定义定义了头文件,如下所示.

struct ETHERNET_DIAGNOSTIC_INFO
{
    uint32_t             cmdId; 
    unsigned long        RxCount[MAX_SAMPLES];
    unsigned long        TxCount[MAX_SAMPLES];
    time_t               TimeStamp[MAX_SAMPLES] ;
    char                 LanIpAddress[20];
    char                 LanMacAddress[20];
    char                 WanIpAddress[20];
    char                 LanDefaultGateway[20];
    char                 LanSubnetMask[20];
    char                 LanLease[5000];
};
Run Code Online (Sandbox Code Playgroud)

基本上我删除了C++ guard和typedef,并使用client.cpp文件中的以下代码从服务器获取结果.

if(recv(sockfd, rxbuf, sizeof(ETHERNET_DIAGNOSTIC_INFO), 0) > 0)
{
    ETHERNET_DIAGNOSTIC_INFO *info = reinterpret_cast<ETHERNET_DIAGNOSTIC_INFO *> (rxbuf);
}
Run Code Online (Sandbox Code Playgroud)

我没有得到正确的结果.结构中的值放错了位置(某些值是正确的,但很多值都放错了位置).我也试过"C"型铸造,但没有用.

我怀疑当服务器以c结构的形式发送数据时,我们不能将缓冲区转换为客户端上的C++结构.这是对的吗?任何人都可以告诉我如何解决这个问题?

fuk*_*hik 8

这种方法存在多个问题:

  1. 服务器和客户端计算机之间的字节顺序可能不同

    然后你需要去实现数字和数字time_t.

  2. 在服务器(c ++)和客户端(C)上编译的代码之间的结构打包可能不同

    然后,您需要使用协议来发送数据,如二进制ASN,protobuf或许多其他.

  3. if(recv(sockfd, rxbuf, sizeof(ETHERNET_DIAGNOSTIC_INFO), 0) > 0) 没有保证recv会准确读取sizeof(ETHERNET_DIAGNOSTIC_INFO)字节数.

    你需要将它包装成while循环(代码是样本,可能是不可编译的):

.

int left = sizeof(ETHERNET_DIAGNOSTIC_INFO);
char *ptr = rxbuf;
int rd;

while(left>0)
{
    rd=recv(sockfd, ptr, left, 0);
    if(rd==0)
    {
        if(left>0) return SOCKET_CLOSED_PREMATURELY;
        else return SOCKET_DONE;
    } else if(rd==-1 && errno==EAGAIN) {
        //do again
        continue; 
    } else if(rd==-1 && errno!=EAGAIN) {
       return SOCKET_ERROR;
    }
    left = left - rd;
    ptr=ptr+rd;
}
Run Code Online (Sandbox Code Playgroud)

发送二进制数据的正确方法是使用protobuf或apache thrift,或ASN或自己发明一些东西.