#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*
.
Однако… Несколько других несвязанных моментов:
-
gethostbyname
может произойти сбой. На самом деле это случается довольно часто, скажем, когда пользователь вводит фиктивный адрес. Ваша программа завершит работу, когда это произойдет. Проверьте, вернулось ли оноNULL
, чтобы избежать этого. -
На самом деле,
gethostbyname
был заменен наgetaddrinfo
. Используйте это. Это обеспечит вам независимость от протокола, так что вы не будете привязаны к IPv4. Он также возвращает вамstruct sockaddr*
, поэтому вам не нужно выполнять уродливое приведение.
Комментарии:
1. 1 все трудности OP исчезли бы, просто удалив эти устаревшие интерфейсы.
Ответ №4:
Если бы это был просто const
, это сработало бы, но очевидно, что sockaddr
и sockaddr_in
— это разные типы.
Комментарии:
1. Да, но забывание приведения должно вызывать только предупреждение, а не ошибку.