2012-08-07 29 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

相關問題