當我嘗試連接到我的ipv4服務器時出現錯誤。目前,ios應用程序用戶需要輸入服務器的IP地址,端口和帳戶信息。iOS套接字IPv6支持
然後,ios應用程序會調用SocketSender類中的Connect(包含在標頭搜索路徑中),然後調用Socket.h的connect函數,然後檢查結果。
連接 - 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。任何幫助將不勝感激,因爲我一直在過去一週卡住測試。此外,如果有人知道如何調試XCode上的SocketSender.cpp,這將是很多的幫助。
你到底是有什麼問題有?你說有錯誤,但你沒有說錯誤是什麼,或者哪一行代碼報告錯誤。在任何情況下,您的'gethostbyname()'代碼都被打破。您沒有檢查'hostinfo-> h_addrtype'字段以確保IP地址(是),複數)與您期望的類型相同,並且您沒有在整個列表中循環。 'gethostbyname()'可能會返回* IPv4或IPv6地址,並且您無法控制報告的類型。 'getaddrinfo()'提供了控制權,所以是的,使用它。 –
@RemyLebeau當我使用getaddrinfo()並遍歷列表並使用socket.h(網絡庫)中的連接函數進行連接時。連接函數返回-1,這意味着它沒有連接。爲了澄清,我正在嘗試爲ipv6執行與socketsender.cpp相同的操作,但它沒有連接。 – 3rdeye7
你有沒有嘗試檢查'errno'呢?它會告訴你爲什麼'connect()'失敗。您是否嘗試記錄'getaddrinfo()'報告的IP地址?您的設備是否連接到可以訪問這些IP地址的網絡? –