【发布时间】:2013-12-01 02:55:19
【问题描述】:
我正在为班级项目编写一个小型电子邮件服务器/客户端。当我在同一台机器上运行客户端和服务器时,一切正常。当我在 x86 机器上运行服务器并在 x64 机器上运行客户端时,我陷入了阅读困境。当我在 x64 机器上运行服务器并在 x86 机器上运行客户端时,读取完成,但是当我打印字符串时,它是空白的。以下是我用来阅读的功能
/*----------------------------------------------------------------*/
int readn(int sd, char *buf, int n) {
printf("readn via utils. %d, %s, %d\n", sd, buf, n);
int toberead;
char * ptr;
toberead = n;
ptr = buf;
while (toberead > 0) {
int byteread;
fprintf(stderr, "toberead: %d, byteread: %d\n",toberead, byteread );
byteread = read(sd, ptr, toberead);
fprintf(stderr, "toberead: %d, byteread: %d\n",toberead, byteread );
if (byteread <= 0) {
fprintf(stderr, "byteread val: %d",byteread);
if (byteread == -1)
perror("read");
raise (6);
return (0);
}
toberead -= byteread;
ptr += byteread;
}
fprintf(stderr, "Finished readn. %s\n", buf);
return (1);
}
其他使用或影响 readn 的实用函数
/*----------------------------------------------------------------*/
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.\n");
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);
}
在第一种情况下(x86 到 x64)的输出如下。
readn via utils. 3, , 1
toberead: 1, byteread: 0
toberead: 1, byteread: 1
Finished readn.
readn via utils. 3, , 8
toberead: 8, byteread: 1
toberead: 8, byteread: 8
Finished readn.
readn via utils. 3, , 57
toberead: 57, byteread: 58
toberead: 57, byteread: 53
toberead: 4, byteread: 53
从x64到x86的函数输出如下
readn via utils. 3, , 1
toberead: 1, byteread: -1079631112
toberead: 1, byteread: 1
Finished readn.
readn via utils. 3, , 4
toberead: 4, byteread: 1
toberead: 4, byteread: 4
Finished readn.
readn via utils. 3, , 57
toberead: 57, byteread: -1079631112
toberead: 57, byteread: 57
Finished readn.
Reading packet complete succesfully.
>>
数据应该在>>之后打印
如果我的问题清楚或是否有任何其他信息,请告诉我。我花了整整 2 天的时间试图解决这个问题,但徒劳无功。
更新:调用 readn 的函数被更新。
【问题讨论】:
-
第一个
fprintf(stderr, ...引入了未定义的行为,因为byteread是在未初始化的情况下访问的。执行int byteread = 0;将解决此问题并且使日志输出更有意义。 -
还
read()返回ssize_t并采用size_t而不是int代码所做的那样。这个错误会使代码无法处理大量数据。 -
如果接收到的数据没有将
0作为最后一个字符,那么fprintf(stderr, "Finished readn. %s\n", buf);这一行也会引入未定义的行为。将其更改为逐字节打印缓冲区或测试尾随0并在打印“字符串”之前“手动”添加它。