2017-10-05 52 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