C++ 套接字 recv() 系统调用返回 -1

Posted

技术标签:

【中文标题】C++ 套接字 recv() 系统调用返回 -1【英文标题】:C++ Sockets recv() syscall returning -1 【发布时间】:2011-11-13 10:51:38 【问题描述】:

我目前在服务器和客户端之间传递消息时遇到问题。 据我所知,我正确地遵循Beej's Socket Programming Tutorial 概述的套接字编程最佳实践。

当我运行这两个进程时,recv() 系统调用返回 -1(一个错误),而不是接收到的字节数。此外,在尝试输出 buf 时,还有一堆 gobbledygook 字符。这是有道理的,因为错误。

我想知道是否有人可以引导我朝着正确的方向前进,为什么我在使用 recv() 时遇到问题?以下是相关代码sn-ps。

服务器:

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);

客户:

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;

以下是服务器的输出:

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æ

以下是客户端的输出:

sockfd 4
5

【问题讨论】:

【参考方案1】:

您在错误的套接字上调用recv。你需要在newfdrecv

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

现在已经不碍事了,

据我所知,我正确地遵循了套接字的最佳实践 编程

我完全不同意。

您没有检查listenbindgetaddrinfo 等的退货状态 您的程序中没有strerrorperror

【讨论】:

非常感谢。我对这种疏忽感到惊讶。另外,我将添加返回状态和错误输出。诚然,我对此有点懒惰。【参考方案2】:

你想使用从accept()返回的socket来recv()

byte_count  =  recv(newfd,  buf,  sizeof  buf,  0); 

【讨论】:

谢谢!今晚快速回复.. 嘘【参考方案3】:

也许我不应该将其写为答案,而应作为评论。尽管如此,恕我直言,您对getaddrinfo() 的使用对我来说似乎是错误的。

在客户端,它应该被调用,然后遍历结果,直到可以建立连接。

所以

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

通过这种方式,您可以检查所有可能的连接。

在服务器端,使用getaddrinfo() 是相当不寻常的。通常,您将创建一个 IPv6 套接字,并通过使用 setsockopt() 取消设置 IPV6_V6ONLY 标志来启用它以侦听 IPv4。通过这种方式,套接字同时侦听 IPv6 和 IPv4。 (唉,不是在 WIndows XP AFAIK 上。)

【讨论】:

服务端调用getaddrinfo没什么问题,还是一个方便的API。 AI_PASSIVE 应该已经设置好了。 谢谢!这对我来说是全新的,所以我have a question about that...【参考方案4】:

sockfd仅用于监听客户端,newfd用于数据传输。

【讨论】:

以上是关于C++ 套接字 recv() 系统调用返回 -1的主要内容,如果未能解决你的问题,请参考以下文章

套接字之recv系统调用

为啥对 recv 的重叠调用会返回 ERROR_NO_MORE_ITEMS(259)?

C++:尽管发送了数据,但 Recv 永远阻塞

在 C++ 中通过 'recv' 和 'MSG_PEEK' 获取套接字中可用的字节数

如何中止winsock阻塞调用?

recv 问题时套接字关闭