Я получаю сообщение об ошибке, когда пытаюсь подключиться к своему серверу ipv4. В настоящее время пользователи приложения ios должны ввести IP-адрес своего сервера, порт и информацию об учетной записи.
Затем приложение ios вызывает Connect для класса SocketSender (включенного в путь поиска заголовка), который, в свою очередь, вызывает функцию подключения Socket.h, а затем проверяет результаты.
Подключиться — SocketSender.cpp
bool SocketSender::Connect (const char *host, int port, CApiError &err)
{
errno = 0;
struct hostent *hostinfo;
hostinfo = gethostbyname (host);
if (!hostinfo) {
#ifdef PLATFORM_WIN32
m_nLastErrorNo = SOCKET_ERRNO();
err.SetSystemError(m_nLastErrorNo);
#else
/* Linux stores the gethostbyname error in h_errno. */
m_nLastErrorNo = EINVAL; // h_errno value is incompatible with the "normal" error codes
err.SetError(FIX_SN(h_errno, hstrerror(h_errno)), CATEGORY_SYSTEM | ERR_TYPE_ERROR);
#endif
return false;
}
socket_fd = socket (AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
m_nLastErrorNo = SOCKET_ERRNO();
err.SetSystemError(m_nLastErrorNo);
return false;
}
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons (port);
address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
int result;
SetSocketOptions();
result = connect (socket_fd, (struct sockaddr *) &address, sizeof (address));
if (result == -1) {
if (IS_IN_PROGRESS()) {
fd_set f1,f2,f3;
struct timeval tv;
/* configure the sets */
FD_ZERO(&f1);
FD_ZERO(&f2);
FD_ZERO(&f3);
FD_SET(socket_fd, &f2);
FD_SET(socket_fd, &f3);
/* we will have a timeout period */
tv.tv_sec = 5;
tv.tv_usec = 0;
int selrez = select(socket_fd + 1,&f1,&f2,&f3,&tv);
if (selrez == -1) { // socket error
m_nLastErrorNo = SOCKET_ERRNO();
Disconnect(true);
err.SetSystemError(m_nLastErrorNo);
return false;
}
if (FD_ISSET(socket_fd, &f3)) { // failed to connect ..
int sockerr = 0;
#ifdef PLATFORM_WIN32
int sockerr_len = sizeof(sockerr);
#else
socklen_t sockerr_len = sizeof(sockerr);
#endif
getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &sockerr_len);
if (sockerr != 0) {
m_nLastErrorNo = sockerr;
} else {
#ifdef PLATFORM_WIN32
m_nLastErrorNo = ERROR_TIMEOUT; // windows actually does not specify the error .. is this ok?
#else
m_nLastErrorNo = ETIMEDOUT;
#endif
}
Disconnect(true);
err.SetSystemError(m_nLastErrorNo);
return false;
}
if (!FD_ISSET(socket_fd, &f2)) { // cannot read, so some (unknown) error occured (probably time-out)
int sockerr = 0;
#ifdef PLATFORM_WIN32
int sockerr_len = sizeof(sockerr);
#else
socklen_t sockerr_len = sizeof(sockerr);
#endif
getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &sockerr_len);
if (sockerr != 0) {
m_nLastErrorNo = sockerr;
} else {
#ifdef PLATFORM_WIN32
m_nLastErrorNo = ERROR_TIMEOUT; // windows actually does not specify the error .. is this ok?
#else
m_nLastErrorNo = ETIMEDOUT;
#endif
}
Disconnect(true);
err.SetSystemError(m_nLastErrorNo);
return false;
}
#ifndef PLATFORM_WIN32 // FIXME: is the same needed for windows ?
// unix always marks socket as "success", however error code has to be double-checked
int error = 0;
socklen_t len = sizeof(error);
if (getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
err.SetSystemError();
return false;
}
if(error != 0) {
m_nLastErrorNo = error;
Disconnect(true);
err.SetSystemError(m_nLastErrorNo);
return false;
}
#endif
} else {
m_nLastErrorNo = SOCKET_ERRNO();
Disconnect(true);
err.SetSystemError(m_nLastErrorNo);
return false;
}
}
m_nIP = ntohl(address.sin_addr.s_addr);
m_bServerSocket = false;
return true;
}
Это оригинальная версия, которая работала без проблем. Когда я изменил приведенное выше, чтобы использовать AF_INET6 и in_addr6->sin6_addr, я продолжал получать ошибки, и приложению не удавалось подключиться. Я пытался использовать getaddrinfo, но это все еще не соединилось.
struct addrinfo hints, *res, *res0;
int error;
const char *cause = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_DEFAULT;
error = getaddrinfo(host, "PORT", &hints, &res0);
if (error) {
errx(1, "%s", gai_strerror(error));
/*NOTREACHED*/
}
socket_fd = -1;
printf("IP addresses for %s:\n\n", host);
int result;
void *addr;
char *ipver;
for (res = res0; res!=NULL; res = res->ai_next) {
socket_fd = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
if (socket_fd < 0) {
cause = "socket";
continue;
}
if ((result = connect(socket_fd, res->ai_addr, res->ai_addrlen)) < 0) {
cause = "connect";
close(socket_fd);
socket_fd = -1;
continue;
}
// get the pointer to the address itself,
// different fields in IPv4 and IPv6:
if (res->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
SetSocketOptions();
break; /* okay we got one */
}
Мне нужно сделать его обратно совместимым с ipv6 и ipv4. Любая помощь будет высоко оценена, так как я застрял в тестировании на прошлой неделе. Также, если кто-нибудь знает, как отлаживать SocketSender.cpp в XCode, это очень поможет.
gethostbyname()
изначально был взломан. Вы не проверяли полеhostinfo->h_addrtype
, чтобы убедиться, что IP-адрес(а) (да, во множественном числе) имеют тот же тип, который вы ожидаете, и вы не перебирали весь список.gethostbyname()
может возвращать либо адреса IPv4, либо IPv6, и вы не можете контролировать, какой тип отчетов.getaddrinfo()
обеспечивает этот контроль, так что да, используйте его. - person Remy Lebeau   schedule 14.07.2016errno
? Он расскажет вам, почемуconnect()
терпит неудачу. Вы пробовали регистрировать IP-адреса, о которых сообщаетgetaddrinfo()
? Подключено ли ваше устройство к сети, которая может получить доступ к этим IP-адресам? - person Remy Lebeau   schedule 14.07.2016getaddrinfo
, и вы передаете литерал IPv4 и числовой порт вgetaddrinfo
, возможно, вы столкнулись с эта ошибка, возвращающая структуры с 0 портами; вам нужно вручную установить правильное количество портов после того, как вы получите структуры, чтобы обойти эту ошибку. - person user102008   schedule 14.07.2016