【发布时间】: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);
}
【问题讨论】:
-
切勿在数据包或类似数据中使用
int或long。这就是uint32_t和朋友们的目的。 -
不要使用
structs作为网络协议。您刚刚发现了一个原因,还有大约五个其他原因。为自己设计一个以八位字节定义的有线协议,并编写代码来发送和接收它。 -
就像 EJP 所说,基本上......
-
对网络协议使用结构体并没有错,你只需要确保它们在两端使用相同的数据对齐方式,使用直接
#pragma语句或跨平台pshpack...头文件.
标签: c linux sockets 32bit-64bit