C++ Sockets recv() syscall returning -1

2019-08-26 11:06发布

I'm currently having a problem passing messages between a server and client. As far as I know, I am properly following best practices for socket programming outlined by Beej's Socket Programming Tutorial.

When I run the two processes, the recv() syscall returns -1 (an error), rather than the number of bytes received. Also when trying to output the buf, there are a bunch of gobbledygook characters. Which makes sense, because of the error.

I'm wondering if someone could steer me in the right direction as to why I am having issues with recv()? The following are relevant code snippets.

Server:

struct sockaddr_storage their_addr;
socklen_t addr_size;
int sockfd, newfd, byte_count, status;
char buf[512];
struct addrinfo hints,  *res;

//  first,  load  up  address  structs  with  getaddrinfo():
memset(&hints,  0,  sizeof  hints);
hints.ai_family  =  PF_INET;
hints.ai_socktype  =  SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

// get address info, print stuff if error
if((status = getaddrinfo("nunki.usc.edu",  "21957",  &hints,  &res)) !=0){
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    exit(1);
}

//  make  a  socket:
if((sockfd  =  socket(res->ai_family,  res->ai_socktype,  res->ai_protocol)) == -1){
    cout << "socket fail" << endl;
}

// bind the socket to the port
bind(sockfd, res->ai_addr, res->ai_addrlen);

// required output
cout << "Phase1: Login server has TCP port number " << "21957 " 
     << "and IP address " << getIPfromHost("nunki.usc.edu") << endl;

// listen for incoming connections
listen(sockfd, 10);
cout << "after listen" << endl;

// halt until receipt 
addr_size = sizeof(their_addr);
newfd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);
cout << "after accept" << endl;

// Now  that  we're  connected,  we  can  receive  some data
byte_count  =  recv(sockfd,  buf,  sizeof  buf,  0); 
printf("recv()'d  %d  bytes  of  data  in  buf\n",  byte_count);
printf("Msg is %s\n", buf);

Client:

struct addrinfo hints,  *res;
int  sockfd;

//  first,  load  up  address  structs  with  getaddrinfo():
memset(&hints,  0,  sizeof  hints);
hints.ai_family  =  AF_INET;
hints.ai_socktype  =  SOCK_STREAM;
getaddrinfo("nunki.usc.edu",  "21957",  &hints,  &res);

//  make  a  socket:
if((sockfd  =  socket(res->ai_family,  res->ai_socktype,  res->ai_protocol)) == -1){
    cout << "socket fail" << endl;
}

// attempt connection to port
if(connect(sockfd,  res->ai_addr,  res->ai_addrlen) == -1){
    cout << "connect fail" << endl;
}

// send message to server
cout << "sockfd " << sockfd << endl;
int byte_count = send(sockfd, "Hello", 5, 0); 
cout << byte_count << endl;

The following is the output for Server:

Phase1: Login server has TCP port number 21957 and IP address 68.181.201.3
after listen
after accept
recv()'d  -1  bytes  of  data  in  buf
Msg is ÿhÿ?sÈ
Glæ

The following is the output for Client:

sockfd 4
5

4条回答
该账号已被封号
2楼-- · 2019-08-26 11:35

Maybe I shouldn't write this as an answer, but as a comment. Nevertheless, IMHO your use of getaddrinfo() seems wrong to me.

  • On the client side, it is supposed to be called and then iterated through the results until a connection can be established.

    so

    struct addrinfo * r2
    sockfd = -1;
    for (r2=res; r2; r2=r2->ai_next) {
        //  make  a  socket:
        if((sockfd  =  socket(res->ai_family,  res->ai_socktype,  res->ai_protocol)) == -1){
            continue; // next result
        }
    
        // attempt connection to port
        if(connect(sockfd,  res->ai_addr,  res->ai_addrlen) == -1){
            close(sockfd);
            sockfd = -1;
            continue;
        }
    }
    if (sockfd == -1) {
        // do error handling
    }
    

    In this way, you can check all possible connections.

  • On the server side, it is rather unusual to use getaddrinfo(). Normally, you would create an IPv6 socket and enable it to listen for IPv4 as well by using setsockopt() to unset the IPV6_V6ONLY flag. In this way, the socket listens to both IPv6 and IPv4. (Alas, not on WIndows XP AFAIK.)

查看更多
▲ chillily
3楼-- · 2019-08-26 11:38

You are calling recv on the wrong socket. You need to recv on newfd:

byte_count = recv(newfd, buf, sizeof buf, 0); /* newfd instead of sockfd. */

Now that that's out of the way,

As far as I know, I am properly following best practices for socket programming

I completely disagree.

  • You are not checking return statuses for listen, bind, getaddrinfo etc
  • There's not strerror or perror in your program
查看更多
Fickle 薄情
4楼-- · 2019-08-26 11:40

The sockfd is just useed for listening the clients, newfd is used for data transmitting.

查看更多
smile是对你的礼貌
5楼-- · 2019-08-26 11:43

You want to recv() using the socket returned from accept()

byte_count  =  recv(newfd,  buf,  sizeof  buf,  0); 
查看更多
登录 后发表回答