Проблема при компиляции кода подключения к сокету на C

#c #sockets

#c #сокеты

Вопрос:

 struct hostent *lh               = gethostbyname(hostname);

int socketDescriptor             = socket(AF_INET,SOCK_STREAM, 0);

sockaddr_in socketInfo;

memset(amp;socketInfo, 0, sizeof(socketInfo));
socketInfo.sin_family            = AF_INET;
socketInfo.sin_addr.s_addr       = ((in_addr *)(lh->h_addr))->s_addr;
socketInfo.sin_port              = htons(portNumber);

connect(socketDescriptor,amp;socketInfo,sizeof(socketInfo));
  

При попытке компиляции я получаю следующую ошибку:

error: cannot convert ‘sockaddr_in*’ to ‘const sockaddr*’ for argument ‘2’ to ‘int connect(int, const sockaddr*, socklen_t)’

Все выглядит «по правилам», но я чего-то не хватает (очевидно). Что это?

Комментарии:

1. От вашего выстраивания назначений у меня болят глаза.

Ответ №1:

Я думаю, что вы что-то упускаете struct из sockaddr_in socketInfo . Так и должно быть struct sockaddr_in socketInfo .

Также было бы неплохо привести socketInfo к struct sockaddr * .

 connect(socketDescriptor,amp;socketInfo,sizeof(socketInfo));
  

Должно быть

 connect(socketDescriptor,(struct sockaddr *) amp;socketInfo,sizeof(socketInfo));
  

Ответ №2:

   struct addrinfo *server;
  struct addrinfo hints; 

    memset(amp;hints, 0, sizeof(struct addrinfo));/*set hints*/
    hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = 0;
    hints.ai_protocol = 0;          /* Any protocol */

 getaddrinfo(srvname,port,amp;hints,amp;server); /*get server ip fit args*/

 sid = socket(server->ai_family, server->ai_socktype,server->ai_protocol)
 connect(sid,server->ai_addr, server->ai_addrlen)
  

Вот несколько наборов кодов, которые будут работать, и с которых вы можете начать.

Что здесь происходит, так это то, что я настраиваю одну структуру со всей информацией, а затем объединяю ее с дополнительной информацией, чтобы получить одну красивую структуру, в которой все указатели слишком подходят для подключения. надеюсь, это поможет

Комментарии:

1. 1 для getaddrinfo . Обратите внимание, что memset на самом деле не требуется. Вы могли бы просто инициализировать struct sockaddr hints = { 0 };

2. @R: 1 вам обоим. Хотя я думаю, вы имеете в виду struct addrinfo hints = { 0 };

3. Кроме того, если вы вызываете getaddrinfo(), вам лучше вызвать freeaddrinfo()

4. @Nemo @R Спасибо за эту информацию, к вашему сведению, был вызван freeaddrinfo, но я не перечислил его здесь.

Ответ №3:

Интерфейсы сокета, в дополнение к тому, что они очень старые, намеренно сломаны таким образом. sockaddr_* Структуры неявно начинаются с одних и тех же элементов sockaddr , поэтому безопасно приводить их к «базовому» типу. struct sockaddr также имеет sa_family элемент, поэтому вы также можете решить во время выполнения, учитывая, struct sockaddr* к какому «производному» (хотя и не совсем) типу его приводить.

Итак, самое малое, что вы можете сделать, чтобы изменить это, — привести struct sockaddr_in* к struct sockaddr* . Обычно это было бы очень оскорбительно. Но не волнуйтесь; в данном случае это делают все. Возможно, я даже предпочел бы привести к void* , потому что в нем меньше символов, и вы получите неявное преобразование в struct sockaddr* .

Однако… Несколько других несвязанных моментов:

  1. gethostbyname может произойти сбой. На самом деле это случается довольно часто, скажем, когда пользователь вводит фиктивный адрес. Ваша программа завершит работу, когда это произойдет. Проверьте, вернулось ли оно NULL , чтобы избежать этого.

  2. На самом деле, gethostbyname был заменен на getaddrinfo . Используйте это. Это обеспечит вам независимость от протокола, так что вы не будете привязаны к IPv4. Он также возвращает вам struct sockaddr* , поэтому вам не нужно выполнять уродливое приведение.

Комментарии:

1. 1 все трудности OP исчезли бы, просто удалив эти устаревшие интерфейсы.

Ответ №4:

Если бы это был просто const , это сработало бы, но очевидно, что sockaddr и sockaddr_in — это разные типы.

Комментарии:

1. Да, но забывание приведения должно вызывать только предупреждение, а не ошибку.