내 ipv4 서버에 연결하려고하면 오류가 발생합니다. 현재 iOS 앱 사용자는 서버의 IP 주소, 포트 및 계정 정보를 입력해야합니다.iOS 소켓 IPv6 지원
ios 앱은 SocketSender 클래스 (헤더 검색 경로에 포함되어 있음)에서 Connect를 호출합니다.이 클래스는 다시 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와 역 호환이 가능해야합니다. 내가 지난 주 동안 이걸 시험 해본 결과 어떤 도움이라도 대단히 감사 할 것입니다. 또한 누군가가 도움이 많이 Xcode에서 SocketSender.cpp를 디버깅하는 방법을 알고 있다면.
? 오류가 있다고 말하면서 오류가 실제로 무엇인지 또는 오류를보고하는 코드 행을 말하지 않습니다. 어쨌든'gethostbyname()'코드는 처음부터 깨져있었습니다. 'hostinfo-> h_addrtype' 필드를 검사하지 않고 IP 주소 (예, 복수형)가 예상하고있는 것과 동일한 유형이고 전체 목록에서 루핑하지 않았는지 확인했습니다. 'gethostbyname()'은 * IPv4 또는 IPv6 주소를 반환 할 수 있으며, 당신은 어떤 종류의 보고서를 제어 할 수 없습니다. 'getaddrinfo()'는 그 컨트롤을 제공하므로 네, 사용하십시오. –
@RemyLebeau 내가 getaddrinfo()를 사용하고 목록을 반복하고 socket.h (네트워킹 lib)의 connect 함수를 사용하여 연결합니다. connect 함수가 -1을 반환하면 연결되지 않았다는 의미입니다. 명확히하기 위해 ipv6에 대해 socketsender.cpp와 동일한 작업을 수행하려고 시도하고 있지만 연결되지 않았습니다. – 3rdeye7
아직'errno'를 검사 해 보셨습니까? 'connect()'가 실패하는 이유를 알려줄 것입니다. 'getaddrinfo()'가보고하는 IP 주소를 기록하려고 시도 했습니까? 기기가 해당 IP 주소에 도달 할 수있는 네트워크에 연결되어 있습니까? –