С ++ Сокеты recv () системный вызов, возвращающий -1 - PullRequest
0 голосов
/ 13 ноября 2011

У меня сейчас проблема с передачей сообщений между сервером и клиентом. Насколько я знаю, я правильно следую рекомендациям по программированию сокетов, изложенным в Руководстве по программированию сокетов Beej .

Когда я запускаю два процесса, системный вызов recv () возвращает -1 (ошибка), а не количество полученных байтов. Кроме того, при попытке вывести buf, есть куча символов gobbledygook. Что имеет смысл, из-за ошибки.

Мне интересно, если кто-то может направить меня в правильном направлении, почему у меня возникают проблемы с recv ()? Ниже приведены соответствующие фрагменты кода.

Сервер:

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

Ответы [ 4 ]

6 голосов
/ 13 ноября 2011

Вы звоните recv не в ту розетку.Вам нужно recv на newfd:

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

Теперь, когда это не так,

Насколько я знаю, я правильно следую рекомендациям дляпрограммирование сокетов

Я совершенно не согласен.

  • Вы не проверяете статусы возврата для listen, bind, getaddrinfo и т. д.
  • Естьне strerror или perror в вашей программе
2 голосов
/ 13 ноября 2011

Вы хотите использовать функцию recv (), используя сокет, возвращаемый методом accept ()

byte_count  =  recv(newfd,  buf,  sizeof  buf,  0); 
0 голосов
/ 22 августа 2013

sockfd просто используется для прослушивания клиентов, newfd используется для передачи данных.

0 голосов
/ 13 ноября 2011

Может быть, я должен написать это не как ответ, а как комментарий.Тем не менее, ИМХО, ваше использование 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 и включаете его для прослушивания IPv4, используя setsockopt() для сброса флага IPV6_V6ONLY.Таким образом, сокет слушает как IPv6, так и IPv4.(Увы, не в Windows XP AFAIK.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...