2012-08-07 28 views
1

我试图在C中使用TCP套接字编程实现客户机 - 服务器程序通信。 它位于安装了Linux操作系统的两台64位机器之间。 我想在两个进程之间传递一个c-struct。两个64位机器之间的TCP套接字编程

为此,我尝试使用一个pack - unpack()functioanlity。

请考虑下面的代码snipt

/*--------------------------------------------------------- 
on the sending side I have: 
---------------------------------------------------------*/ 

struct packet { 
int64_t x; 
int64_t y; 
int64_t q[maxSize]; 
} __attribute__((packed)); 

int main(void) 
{ 
// build packet 
struct packet pkt; 
pkt.x = htonl(324); 
pkt.y = htonl(654); 
int i; 
for(i = 0; i< maxSize; i++){ 
    pkt.q[i] = i; **// I also try pkt.q[i] = htonl(i);** 
} 
    // and then do the send 
} 

/*----------------------------------------------------------------------------- 
in the receiving side: 
-----------------------------------------------------------------------------*/ 
struct packet { 
int64_t x; 
int64_t y; 
int64_t q[maxSize]; 
} __attribute__((packed)); 

static void decodePacket (uint8_t *recv_data, size_t recv_len) 
{ 
// checking size 
if (recv_len < sizeof(struct packet)) { 
    fprintf(stderr, "received too little!"); 
    return; 
} 

struct packet *recv_packet = (struct packet *)recv_data; 

int64_t x = ntohl(recv_packet->x); 
int64_t y = ntohl(recv_packet->y); 
int i; 
printf("Decoded: x=%"PRIu8" y=%"PRIu32"\n", x, y); 

for(i=0;i<maxSize;i++){ 
    **//int64_t res = ntohl(recv_packet->q[i]); I also try to print res**   
    printf("%"PRIu32"\n" , recv_packet->q[i]);  
} 
} 

int main(int argc, char *argv[]){ 
// receive the data and try to call decodePacket() 
int8_t *recv_data = (int8_t *)&buf; //buf is the data received 
size_t recv_len = sizeof(buf); 
**decode_packet(recv_data, recv_len);** 
} 

//----------------------------------------------------------------------------- 

现在的问题是,我正确地接收到在结构中的x和y的值, 但在结构中的阵问:我收到了一个奇怪的编号,可能的内存碎片值,(我尝试使用memset()在从另一端接收数据之前用零填充数组,在这种情况下接收全零值)

我不明白为什么我没有收到结构中数组的正确值。

请注意,我尝试与出htonl(),而投入结构, 而在另一侧前填充阵列:以与出再用ntohl(),而阵列从结构解码

任何帮助将理解的,

+0

您的接收端有几种不匹配的打印格式 - 这会导致未定义的行为。修复这些并再试一次? – 2012-08-07 17:14:14

+1

由于问题很可能出现在发送或接收代码中,因此您忽略了重要的位。一种可能性是该结构需要在两端声明为打包(取决于你如何尝试发送/接收它)。 – 2012-08-07 17:15:09

+0

是的。而这在编译器插入不同填充的两个Linux之间甚至不起作用。你最好连续化数值。甚至不要尝试直接转移结构。 – 2012-08-07 17:17:47

回答

3
size_t recv_len = sizeof(buf); 
decode_packet(recv_data, recv_len); 

这段代码保证了错误的大小被传递给decode_packet。因此,当decode_packet继续检查recv_len < sizeof(struct packet)时,该测试毫无意义 - 无论接收到多少字节,它总是会通过。

您需要从recv调用返回的值中获取大小。我最好的猜测是,你收到的字节数比你期望的要少。


虽然发送和接收结构非常方便,但它通常是无用的练习。手动序列化数据或使用某些明确的机制可能是一条可行的路。

+0

你的猜测是正确的,我发送了几个字节,并试图收到它,我的错误。感谢您的帮助 – LeTex 2012-08-08 08:31:58

1

您没有向我们展示sendrecv部分,这更可能是错误的。我的猜测是你正确地接收了数组中的第一项,并且它们在某个时候“变成”垃圾,是不是?

好,@cnicutar是正确的,但让我延长一点点......

首先,当你调用send你必须检查返回值,看看是否所有字节传输。如果您的结构很大(例如大于底层套接字缓冲区),则需要多个调用来传输整个结构。与recv,相同,不要指望你会在一个recv调用得到整个消息,不要指望每个recv都会收到相同数量的数据,这些数据是由相应的send调用发送的。总是检查接收到的字节数,如有必要,再次调用recv(指向传入缓冲区中的正确位置并减少要接收的字节数)。

因此,可能发生的情况是,您没有收到足够的数据(也许您甚至不会传输所有数据),只有传入缓冲区的开始部分正在填充。因此,其余的结构是垃圾或(当你打电话memset)保持零初始化。

同时注意到sendrecv返回ssize_t而不是size_t作为负值是可能的(以指示错误)。

+0

您的答案是正确的,我发送了几个字节并试图收到所有的错误信息。谢谢你的帮助 – LeTex 2012-08-08 08:33:15

相关问题