C++ WinSock2:连接()调用上的 WSA_INVALID_HANDLE
Posted
技术标签:
【中文标题】C++ WinSock2:连接()调用上的 WSA_INVALID_HANDLE【英文标题】:C++ WinSock2: WSA_INVALID_HANDLE on connect() call 【发布时间】:2013-09-15 15:21:55 【问题描述】:美好的一天!
我是高级语言的一些经验丰富的程序员,但这是我第一次深入研究低级语言的套接字代码,所以请多多包涵。
connect()
调用时我似乎遇到了错误。在我的主要功能中,WSAGetLastError()
打印出这是错误号 6,根据 MSDN 是 WSA_INVALID_HANDLE
。这似乎很奇怪,因为MSDN page for the connect()
function 上没有详细说明该特定错误代码(除非我要失明),而且我的谷歌搜索都没有结论
我正在使用自定义 socket_t 结构,因为我的代码被设计为(最终)是跨平台的。从主代码页调用socket_connect()
函数。
socket_t
定义:
typedef struct
//windows-specific
SOCKADDR_IN *addr_in;
u_long mode;
SOCKET socket;//acutal SOCKET structure
// General
bool listening;//set to true if actively listening
bool thread_terminate;//when boolean is set to true, listening thread terminates
void (*error_callback) (int);
http_response_t * response;
socket_t;
socket_connect()
函数:
//see socket_t definition in socket.h
//returns 0 on success, SOCKET_ERROR on WinSock failure, positive error code on ANSI DNS failure
int socket_connect(socket_t * sock, char * addr, int port)
//bear in mind sock is the custom socket_t structure. sock->socket is the actual SOCKET structure.
//pardon the nomenclature. rookie code.
//DNS lookup structures
struct addrinfo * res = NULL;// Result of the getaddrinfo() call
struct sockaddr_in * sockaddr_v4 = NULL;// IPv4 sockaddr structure
// So-called "hints" structure detailed in the getaddrinfo() MSDN page.
// I guess it contains information for the DNS lookup.
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
//Perform DNS lookup
DWORD getaddrinfo_res = getaddrinfo(addr, "80\0", &hints, &res);//hard-code Port number for now...
if(getaddrinfo_res != 0) return getaddrinfo_res;//positive DNS error code
//debug information
std::cout << "DNS lookup responses:" << std::endl;
//for each
int i = 0;//counter
for(struct addrinfo * ptr = res; ptr != NULL; ptr = ptr->ai_next)
std::cout << "Response number " << i + 1 << std::endl;
std::cout << "Flags: " << ptr->ai_flags << std::endl;
std::cout << "Family: ";
switch(ptr->ai_family)
case AF_INET:
sockaddr_v4 = (struct sockaddr_in *) ptr->ai_addr;//set current address
sock->addr_in = sockaddr_v4;//set socket address
std::cout << "AF_INET (IPv4)" << std::endl;
std::cout << "Addr: " << inet_ntoa(sockaddr_v4->sin_addr) << std::endl;
break;
case AF_UNSPEC:
std::cout << "UNSPECIFIED" << std::endl;
break;
default:
std::cout << "UNKNOWN\t(" << ptr->ai_family << ")" << std::endl;
break;
i++;
//initialize actual SOCKET
sock->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// TCP/IP, stream-oriented, and TCP rather than UDP; respectively
if(sock->socket == INVALID_SOCKET) return SOCKET_ERROR;
//actual connection
std::cout << WSAGetLastError() << std::endl;
int connect_res = connect(sock->socket, (SOCKADDR *) sockaddr_v4, sizeof(sockaddr_v4));///have to convert SOCKADDR_IN to a SOCKADDR pointer here. Not sure why.
if(connect_res == SOCKET_ERROR) return SOCKET_ERROR;
//make nonblocking
/*
sock->mode = 1;
int ioctl = ioctlsocket(sock->socket, FIONBIO, &(sock->mode));//I/O Control Socket. Not sure what FIONBIO means. pointer to sock->mode = 1 ensures nonblockingness.
if(ioctl == SOCKET_ERROR) return SOCKET_ERROR;
*/// (include this?)
return 0;
socket_connect()
函数调用:
int connect_res = conley::socket_connect(sock, "www.google.com", 80);
if(connect_res > 0) std::cout << "DNS ERR " << connect_res << std::endl << std::endl;
if(connect_res < 0) std::cout << "CONNECT ERR " << WSAGetLastError() << std::endl << std::endl;
if(connect_res == 0) std::cout << "Connected" << std::endl << std::endl;
感谢您的宝贵时间! - 杰克
【问题讨论】:
小问题先。您是否使用WSAStartup()
正确初始化了 WinSock?
@WhozCraig 是的,我相信。
【参考方案1】:
当您调用 connect 时,sockaddr_in
传递的大小错误。
改变这个:
int connect_res = connect(sock->socket, (SOCKADDR *) sockaddr_v4, sizeof(sockaddr_v4));
// wrong size ^^^^^^^^^^^
到这里:
int connect_res = connect(sock->socket, (SOCKADDR *) sockaddr_v4, sizeof(*sockaddr_v4));
// right size ^^^^^^^^^^^
除此之外,您的程序还有一个不同的错误,即 getaddrinfo()
的持久性 - 在您的 sock
结构中返回指针。这应该按值复制到sock
拥有的内存中。它将与此示例一起使用,因为它是如此孤立,但应该更改它。
【讨论】:
啊,现在完全有道理了。谢谢!以上是关于C++ WinSock2:连接()调用上的 WSA_INVALID_HANDLE的主要内容,如果未能解决你的问题,请参考以下文章
winsock2:服务器端代码调用`accept()`后如何获取已连接客户端的ipv4/ipv6地址