我正在为我的分布式系统类工作。我是C.S.的硕士生,但我在编程方面的专长是.NET,我正在开发一个项目,需要一些相当普遍的Unix知识,这让我很沮丧。
该任务正在实施刷新通道协议API。所以我正在编写一个小型函数库,其他应用程序可以使用它来实现刷新通道通信。我进行了设置,以便在调用init函数时,它会将子进程作为传入消息的服务器。子进程通过管道将传入数据发送给父进程与父进程通信。
如果一次发送和接收一条消息,则此工作正常;如,
发送 - >接收 - >发送 - >接收 - >等
但是,如果在进行任何接收之前发送了多条消息;如,
发送 - >发送 - >发送 - >接收
然后它搞砸了。具体来说,第一条消息被正确接收,但当我去接收第二条消息时,程序挂起并需要被杀死。我已经做了大量的在线搜索工作,并且已经花了好几个小时,但没有取得多大进展。整个程序太大而无法在此显示,但这里是最相关的部分。这是我让服务器前进和接收消息的部分。注意这一行
写(fd [1],缓冲区,(strlen(缓冲区)+1));
- 我认为这是一个很好的候选人,可以成为问题的根源,但不知道该怎么做。 (尝试过fwrite(),但根本没用。)
fd = malloc(2 * sizeof(int));
int nbytes;
if (pipe(fd) < 0) {
perror("Could not create pipe");
return -1;
}
pID = fork();
if (pID < 0) {
perror("Failed to fork");
return -1;
} else if (pID == 0) { // child
close(fd[0]); // close input side of pipe
int cc;
int fsize;
struct sockaddr_in from;
int serials[500];
int i;
for (i = 0; i < 500; i++) serials[i] = 0;
char buffer[2048];
while (1) {
fsize = sizeof(from);
cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize);
if (cc < 0) perror("Receive error");
datagram data = decodeDatagram(buffer);
if (serials[data.serial] == 0) {
write(fd[1], buffer, (strlen(buffer)+1));
serials[data.serial] = 1;
}
}
} else { // parent
close(fd[1]); // close output side of pipe
return 0;
}
(“serials”数组用于不转发重复消息,因为消息被多次发送以提高可靠性。我知道这个数组的固定大小不是好习惯,但是这个分配的测试不会发送很多消息,所以在这种情况下没问题。)
接收函数的开头如下所示:
int fRecv(int* id, char* buf, int nbytes) {
checkDatagramTable(*id);
char* tbuf = malloc((nbytes + 9) * sizeof(char));
int rbytes = read(fd[0], tbuf, nbytes + 9);
“+9”用于容纳与要发送的消息一起打包的附加信息,用于刷新通道排序。这也是一个相当粗略的区域,但是分配更多的空间来确保这个问题没有帮助。
我知道这里有很多无关紧要的东西,对其他函数等的引用。但问题肯定在于我如何管理数据,因此我的问题的根源应该在某处。
预先感谢您的协助;真的很感激。
答案 0 :(得分:1)
这看起来很可疑。 (数据包中的内容是什么?它们可以是二进制的)数据报的typedefinition在哪里?
fsize = sizeof(from);
cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize);
if (cc < 0) perror("Receive error");
datagram data = decodeDatagram(buffer);
if (serials[data.serial] == 0) {
write(fd[1], buffer, (strlen(buffer)+1)); // <-- ????
serials[data.serial] = 1;
}
我试着改为:
write(fd[1], buffer, cc);
更新:
如果消息未终止,则必须明确终止:
(if cc == 2048) cc -= 1;
buffer [cc] = '\0'; // <<--
datagram data = decodedatagram(buffer);
...
此外,建议使用“sizeof buffer”而不是“2048”。
UPDATE2: 您可以通过以下方式测试数据包中的字符串是否真正以null结尾:
unsigned pos;
cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize);
if (cc < 0) perror("Receive error");
for pos=0; pos < cc; pos++) {
if (buff[pos] == 0) break;
}
switch (cc-pos) {
case 0: fprintf (stderr, "No nul byte found in packet: I lose!\n" ); break;
default: fprintf (stderr, "Spurious nul byte found in the middle of packet\n" );
case 1: break;
}
datagram data = decodeDatagram(buffer);
if (serials[data.serial] == 0) {
write(fd[1], buffer, cc);
serials[data.serial] = 1;
}