【问题标题】:Send a packet from 32 bit and Receive in 64 bit machine从 32 位发送数据包并在 64 位机器中接收
【发布时间】:2013-12-17 08:45:24
【问题描述】:

我正在编写一个在不同位机之间交换消息的程序。我的发送、接收和读取函数如下所示。问题是我有一个发送消息的数据包格式。数据包类型决定了消息的类型,如欢迎、数据、用户名等。我从 sd 读取数据包类型,然后读取剩余数据。当我从 32 位发送时,数据包类型将为 x 到 x+4,数据将为 x+4 到依此类推。在接收时,在 64 位机器上,数据包类型从 x 读取到 x+8 和 x+8 作为数据,因此我的读取函数将永远等待以获取指定长度的剩余字节。如何在这段代码中解决这个问题?

/*----------------------------------------------------------------*/

/* messsges received/sent by server */
#define WELCOME_MSG    0
#define USER_NAME     1
#define EMAIL_MSG_TO_SERVER    2
#define EMAIL_MSG_TO_CLIENT 3
#define CLOSE_CON 4
/* structure of a packet */
typedef struct _packet {

    /* packet type */
    char      type;

    /* packet length */
    long      lent;

    /* packet text */
    char *    text;

} Packet;

int readn(int sd, char *buf, size_t n) {
    printf("readn via utils. %d, %s, %d\n", sd, buf, n);
    size_t toberead = n;
    char * ptr = buf;

    while (toberead > 0) {

        int errno_save = 0;

        fprintf(stderr, "toberead: %zu\n", toberead);

        ssize_t  byteread = read(sd, ptr, toberead);
        errno_save = errno;

        fprintf(stderr, "toberead: %zu, byteread: %zd\n", toberead, byteread);

        if (byteread <= 0) {
            fprintf(stderr, "byteread val: %d",byteread);
            if (byteread == -1)
            {
                perror("read");
                errno = errno_save;
            }
            return (0);
        }

        toberead -= byteread;
        ptr += byteread;
    }

    if ('\0' != buf[n]) /* This assumes buf is one byte **larger** then n. */
    {
        buf[n] = '\0';
    }

    fprintf(stderr, "Finished readn. %s\n", buf);
    return (1);
}

/*----------------------------------------------------------------*/



Packet *recvpkt(int sd)
{
    printf("Recvpkt via utils.\n");
    Packet *pkt;

    /* allocate space for the pkt */
    pkt = (Packet *) calloc(1, sizeof(Packet));
    if (!pkt) {
        fprintf(stderr, "error : unable to calloc\n");
        return(NULL);
    }

    /* read the message type */
    if (!readn(sd, (char *) &pkt->type, sizeof(pkt->type))) {
        free(pkt);
        return(NULL);
    }

    /* read the message length */
    if (!readn(sd, (char *) &pkt->lent, sizeof(pkt->lent))) {
        free(pkt);
        return(NULL);
    }
    pkt->lent = ntohl(pkt->lent);

    /* allocate space for message text */
    if (pkt->lent > 0) {
        pkt->text = (char *) malloc(pkt->lent);
        if (!pkt) {
            fprintf(stderr, "error : unable to malloc\n");
            return(NULL);
        }

        /* read the message text */
        if (!readn(sd, pkt->text, pkt->lent)) {
            freepkt(pkt);
            return(NULL);
        }
    }

    fprintf(stderr, "Reading packet complete succesfully.\n");

    /* done reading */
    return(pkt);
}

int sendpkt(int sd, char typ, long len, char *buf)
{
    fprintf(stderr, "Send packet via utils. sd: %d, typ: %c, len: %lu, buf: %s\n", sd, typ, len, buf);
    char tmp[8];
    long siz;

    /* write type and lent */
    bcopy(&typ, tmp, sizeof(typ));
    siz = htonl(len);
    bcopy((char *) &siz, tmp+sizeof(typ), sizeof(len));
    write(sd, tmp, sizeof(typ) + sizeof(len));

    /* write message text */
    if (len > 0)
        write(sd, buf, len);
    return(1);
}

void freepkt(Packet *pkt)
{
    fprintf(stderr, "Freeing packet.\n");
    free(pkt->text);
    free(pkt);
} 

【问题讨论】:

  • 切勿在数据包或类似数据中使用intlong。这就是uint32_t 和朋友们的目的。
  • 不要使用structs 作为网络协议。您刚刚发现了一个原因,还有大约五个其他原因。为自己设计一个以八位字节定义的有线协议,并编写代码来发送和接收它。
  • 就像 EJP 所说,基本上......
  • 对网络协议使用结构体并没有错,你只需要确保它们在两端使用相同的数据对齐方式,使用直接#pragma语句或跨平台pshpack...头文件.

标签: c linux sockets 32bit-64bit


【解决方案1】:

使用stdint.h 标头,该标头定义类型,其名称告诉您它们的大小。它们在任何平台上都将始终保持该大小。

#include <stdint.h>

/* structure of a packet */
typedef struct _packet {
    /* packet type */
    uint8_t  type;
    /* packet length */
    uint32_t lent;
    /* packet text */
    char *   text;
} Packet;

【讨论】:

  • 这有帮助。非常感谢。
  • 数据类型只是问题的一半。数据对齐是另一半。如果您通过套接字发送结构,您不仅必须使用相同的数据类型,而且还必须使用相同的结构对齐方式。除非您单独发送每个结构成员,否则对齐无关紧要。
【解决方案2】:

您需要同意所有各方都遵守的通用二进制格式。我怀疑您知道这一点,但没有意识到某些类型在不同的机器上具有不同的大小。您可能正在使用具有不同尺寸的 long 机器。并且您将长度数据声明为 long 类型。所以在某些机器上是 32 位,而在其他机器上是 64 位。

您可能应该决定使用 32 位整数。您需要使用大小在不同机器上不变的类型。例如 int32_t。

【讨论】:

  • 我知道 int32_t 等,但在使用 C++ 进行了 3 年的错误修复后,我从未意识到它们的重要性。在我自己编写代码之前,我并不关心早点理解这一点。谢谢你帮助我。
  • 看到代码我马上就明白了解决办法,但是你的解释让我有了更多的知识。
猜你喜欢
  • 2014-12-17
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
  • 2012-06-26
  • 2012-05-22
  • 1970-01-01
  • 2011-08-08
  • 2011-04-09
相关资源
最近更新 更多