2017-10-05 51 views
2

問題:我有兩個c程序,一個發送UDP消息,然後得到響應並打印出來。另一個接收UDP消息,修改它並將其發回。我正確接收郵件,正確修改(打印正常)併發送。我在另一端收到消息,但recv返回值爲0.接收UDP消息,但recv返回0

問題:爲什麼我得到正確的消息,但沒有返回消息的長度?這很難檢查我收到了正確的長度消息,因爲我的目標是訪問狀態消息的第320個字節。

我發現this但我沒有使用strlen(),加上緩衝區實際上包含正確的消息。另外,我不斷開連接,因爲我使用的是UDP。

下面是客戶端的代碼:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/socket.h> 
#define SERVICE_PORT 9090 

#define BUFLEN 2048 
#define MSGS 5 

int main(void) 
{ 
    struct sockaddr_in myaddr, remaddr; 
    int fd, i, slen=sizeof(remaddr); 
    char *server = "127.0.0.1"; 
    char buf[BUFLEN]; 
    ssize_t msglen; 


    if ((fd=socket(AF_INET, SOCK_DGRAM, 0))==-1) 
     printf("socket not created\n"); 


    memset((char *)&myaddr, 0, sizeof(myaddr)); 
    myaddr.sin_family = AF_INET; 
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    myaddr.sin_port = htons(7096); 

    if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 
     perror("bind failed"); 
     return 0; 
    } 

    memset((char *) &remaddr, 0, sizeof(remaddr)); 
    remaddr.sin_family = AF_INET; 
    remaddr.sin_port = htons(SERVICE_PORT); 
    if (inet_aton(server, &remaddr.sin_addr)==0) { 
     fprintf(stderr, "inet_aton() failed\n"); 
     exit(1); 
    } 

    char msg[4096]; 
    memset(msg, 0, 4096); 
    for (i=0; i < MSGS; i++) { 
     printf("Sending packet %d to %s port %d\n", i, server, SERVICE_PORT); 
     sprintf(buf, "This is packet %d", i); 
     if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&remaddr, slen)==-1) 
      perror("sendto"); 
     memset(msg, 0, 4096); 
     if(msglen = recv(fd, msg, sizeof(msg), MSG_WAITALL) == -1){ 
      printf("Bad recv\n"); 
     } 
     printf("recieved %d bytes: %s\n", msglen, msg); 
    } 
    close(fd); 
    return 0; 
} 

這裏是服務器的代碼:

#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <unistd.h> 

#include <linux/ip.h> /* for ipv4 header */ 
#include <linux/udp.h> /* for upd header */ 

#define ADDR_TO_BIND "127.0.0.1" 
#define PORT_TO_BIND 9090 
#define SERVICE_PORT 7096 
#define MSG_SIZE 256 
#define HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr)) 

int main(void) { 
    int raw_socket, fd; 
    struct sockaddr_in sockstr, remaddr; 
    socklen_t socklen; 

    int retval = 0; 

    char msg[MSG_SIZE]; 
    ssize_t msglen; 


    if ((raw_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 
     perror("socket"); 
     return 1; 
    } 
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 
     perror("socket"); 
     return 1; 
    } 
    sockstr.sin_family = AF_INET; 
    sockstr.sin_port = htons(PORT_TO_BIND); 
    sockstr.sin_addr.s_addr = inet_addr(ADDR_TO_BIND); 
    socklen = (socklen_t) sizeof(sockstr); 
    if (bind(raw_socket, (struct sockaddr*) &sockstr, socklen) == -1) { 
     perror("bind"); 
     retval = 1; 
     goto _go_close_socket; 
    } 
    if(bind(fd, (struct sockaddr*) &remaddr, socklen) == -1){ 
     perror("bind"); 
    } 
    memset(msg, 0, MSG_SIZE); 
while(1){ 
    if ((msglen = recv(raw_socket, msg, MSG_SIZE, 0)) == -1) { 
     perror("recv"); 
     retval = 1; 
     goto _go_close_socket; 
    } 
    memset((char *) &remaddr, 0, sizeof(remaddr)); 
    remaddr.sin_family = AF_INET; 
    remaddr.sin_port = htons(SERVICE_PORT); 
    if (inet_aton(ADDR_TO_BIND, &remaddr.sin_addr)==0) { 
     fprintf(stderr, "inet_aton() failed\n"); 
     exit(1); 
    } 
    unsigned char buf[4096]; 
    msg[msglen] = '\0'; 
    printf("recieve %d bytes: %s\n", msglen, msg); 
    sprintf(buf, "Your msg is: %s\n",msg); 
    int slen=sizeof(remaddr); 
    if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&remaddr, slen)==-1){ 
     printf("send failed");  
    } 
    printf("sent: %s\n", buf); 
} 
_go_close_socket: 
    close(raw_socket); 

    return retval; 
} 

運行客戶端的輸出是:

Sending packet 0 to 127.0.0.1 port 9090 
recieved 0 bytes: Your msg is: This is packet 0 

Sending packet 1 to 127.0.0.1 port 9090 
recieved 0 bytes: Your msg is: This is packet 1 

Sending packet 2 to 127.0.0.1 port 9090 
recieved 0 bytes: Your msg is: This is packet 2 

Sending packet 3 to 127.0.0.1 port 9090 
recieved 0 bytes: Your msg is: This is packet 3 

Sending packet 4 to 127.0.0.1 port 9090 
recieved 0 bytes: Your msg is: This is packet 4 

的運行服務器的輸出是:

recieve 256 bytes: This is packet 0 
sent: Your msg is: This is packet 0 

recieve 256 bytes: This is packet 1 
sent: Your msg is: This is packet 1 

recieve 256 bytes: This is packet 2 
sent: Your msg is: This is packet 2 

recieve 256 bytes: This is packet 3 
sent: Your msg is: This is packet 3 

recieve 256 bytes: This is packet 4 
sent: Your msg is: This is packet 4 

正如您所見,我在服務器上獲得的消息在開始處更改爲「您的消息是:」,我在客戶端看到該消息,但返回值爲0。爲什麼是這樣?

這段代碼只是稍微修改了示例UDP服務器客戶端的代碼示例,所以如果代碼質量被指出是不好的,我不會被冒犯!

編輯這已經解決了,這是一個將括號中的recv()調用包裹起來的問題,所以條件存儲在msglen中而不是實際的返回值中。見下面

+0

我補充說,搜索堆棧溢出類似的答案後,服務器recv的是,所以我沒惹返回適當的長度用它。然而該標誌對客戶端行爲沒有任何作用@BronislavElizavetin – Tyler

+0

@BronislavElizavetin服務器處於while(1)循環中,並且對客戶端發送的所有5條消息使用相同的套接字,因此如果它被用於接收在第一個0返回之後還有4次? – Tyler

回答

1

我能解決這個問題,看來我忘了換我如果括號recv的聲明,所以我分配msglen的條件

recv(fd, msg, sizeof(msg), 0) == -1 

這當然是0的布爾值返回值不等於-1。

定盤

if((msglen = recv(fd, msg, sizeof(msg), 0)) = -1) 

感謝那些誰試圖對他們的幫助

1

我的回答通常情況下,你應該使用recvfrom的:

從的recv(2)手冊頁:

的的recv()調用通常是在連接的插座只用於(見connect(2))並且與012vNULL src_addr參數與recvfrom()相同。

和插座(2)手冊頁:

SOCK_DGRAM和SOCK_RAW插座允許數據包發送到命名的sendto(2)調用記者。 Datagrams 通常與recvfrom(2)一起收到,它會返回下一個數據報以及其發送者的地址。

使用recv(2)read(2)

爲了使用recv(2)read(2),因爲你exchaning大量的數據報,你必須調用connect(2)第一:

if (connect(fd,remote_addr,sizeof(remote_addr))==-1) { 
    die("%s",strerror(errno)); 
} 

現在你很好去recvwrite

+1

有趣的是,這個人說UDP通常是用recv來完成的。不過,我可以在不使用connect()或recvfrom()的情況下糾正我的問題,但我也會看看recvfrom。我將自己發佈一個答案,我可以解決我的問題 – Tyler