C++ Winsock accept()返回WSAENOTSOCK(代码10038)
希望你今天过得愉快。另一个套接字问题,另一天:) <>我终于安装了微软Visual C++(MSVC++)IDE,加上平台SDK,所以我可以编译Winsock应用程序。 这里漏了一大块东西。在ServerSocket::accept()函数中,它创建了ClientSocket的一个新实例,并将它的套接字文件描述符设置为accept()指定的套接字文件描述符,我也在那里进行了检查,发现描述符在那里也是有效的 在我的ClientSocket::recv()函数中,我(显然)从winsock库中调用recv()函数。我遇到的问题是recv()将我使用的套接字描述符识别为无效,但仅在从我的ServerSocket::accept()返回的服务器端ClientSocket实例上-客户端ClientSocket实例没有问题。我插入了多个调试语句,描述符是有效的 最奇怪的是,如果我在windows上用MinGW gcc/g++编译完全相同的代码,它运行得很好!只有在使用MSVC++时才会出现此问题C++ Winsock accept()返回WSAENOTSOCK(代码10038),c++,visual-c++,sockets,winsock,C++,Visual C++,Sockets,Winsock,希望你今天过得愉快。另一个套接字问题,另一天:) 我终于安装了微软Visual C++(MSVC++)IDE,加上平台SDK,所以我可以编译Winsock应用程序。 这里漏了一大块东西。在ServerSocket::accept()函数中,它创建了ClientSocket的一个新实例,并将它的套接字文件描述符设置为accept()指定的套接字文件描述符,我也在那里进行了检查,发现描述符在那里也是有效的 在我的ClientSocket::recv()函数中,我(显然)从winsock库中调用rec
string ClientSocket::recv(int bufsize) {
if (!isConnected()) throw SocketException("Not connected.");
cout << "SocketRecv: " << (sockfd == INVALID_SOCKET) << " " << sockfd << endl;
vector<char> buffer(bufsize+1, 0);
cout << "SocketRecv1: " << (sockfd == INVALID_SOCKET) << " " << sockfd << endl;
int ret = ::recv(sockfd, &buffer[0], bufsize, 0);
cout << "SocketRecv2: " << (sockfd == INVALID_SOCKET) << " " << sockfd << endl;
// ret is apparently -1 because of "invalid" socket descriptor, but the
// above statements print zero (false) on the (sockfd == INVALID_SOCKET) ! :\
if (ret < 0) {
#ifdef _WIN32
switch((ret = WSAGetLastError())) {
#else
switch(errno) {
#endif
case DECONNREFUSED: // The 'd' prefix means _I_ defined it, i.e. from windows it's
// set to 'WSAECONNREFUSED', but from linux it's set to 'ECONNREFUSED'
throw SocketException("Connection refused on recover.");
break;
case DENOTCONN:
throw SocketException("Not connected.");
break;
case DECONNABORTED:
throw SocketException("Software caused connection abort.");
break;
case DECONNRESET:
throw SocketException("Connection reset by peer.");
break;
default:
//usually this itoa() and char/string stuff isn't here... needed it in
//order to find out what the heck the problem was.
char tmp[21];
string tmp4 = "Unknown error reading socket. ";
string tmp3 = tmp4 + itoa(ret, tmp, 10);
//this throw keeps throwing "Unknown error reading socket. 10038"
throw SocketException(tmp3);
break;
}
} else if (ret == 0) {
connected = false;
return "";
}
return &buffer[0];
}
string ClientSocket::recv(int-bufsize){
如果(!isConnected())抛出SocketException(“未连接”);
cout看起来您没有遵循。任何时候您有一个析构函数,您都需要写入或禁用复制构造函数和赋值运算符
在您的示例用法中:
ClientSocket client = server.accept();
变量client
是从返回值复制构造的。然后析构函数在临时变量上运行,关闭套接字
在C++0x中,您可以添加移动构造函数并解决此问题。现在,您应该实现swap
并使用它:
ClientSocket client;
server.accept().swap(client);
或者将客户端
作为服务器的参数传递。接受
:
ClientSocket client;
server.accept(client);
您可以为ClientSocket
以auto_ptr
的样式编写移动副本构造函数,但我不建议这样做。人们不希望副本构造函数窃取资源。看起来您没有遵循。任何时候,当您有析构函数时,您都需要编写或禁用副本构造函数和assignm耳鼻喉科接线员
在您的示例用法中:
ClientSocket client = server.accept();
变量client
是从返回值复制构造的。然后析构函数在临时变量上运行,关闭套接字
在C++0x中,您可以添加移动构造函数并解决此问题。现在,您应该实现swap
并使用它:
ClientSocket client;
server.accept().swap(client);
或者将客户端
作为服务器的参数传递。接受
:
ClientSocket client;
server.accept(client);
您可以为ClientSocket
编写一个移动副本构造函数,样式为auto\u ptr
,但我不建议这样做。人们不希望副本构造函数窃取资源。仅仅因为您的套接字变量未设置为INVALID\u socket
,并不意味着套接字描述符从WinSock的p中有效透视。显然不是,否则WinSock不会对此抱怨。在您能够调用recv()
(客户端也会出现错误)之前,套接字已关闭
这是因为ServerSocket::accept()
正在按值返回新的ClientSocket
实例。编译器必须为返回值分配对象的第二个副本,但您的ClientSocket
类未定义任何副本构造函数。原始套接字描述符将从第一个ClientSocket
实例复制到第二个实例e、 然后,原始实例在退出时被释放,在第二个实例可以使用它之前关闭套接字。您需要定义一个副本构造函数,该构造函数拥有原始套接字描述符的所有权,并将原始实例的描述符设置为INVALID_socket
,以便其析构函数无法再关闭套接字
与此相关,您的ClientSocket
类中有一个句柄泄漏。您正在ClientSocket
构造函数内部调用WSAStartup()
和socket()
(这不是进行这两个调用的最佳位置)。当ServerSocket::accept()时
接受新客户机,您正在调用ClientSocket::setFd()
使用新的套接字描述符,它替换了在ClientSocket
构造函数中分配的原始套接字描述符,但没有正确释放它。您应该定义第二个ClientSocket
构造函数,该构造函数接受现有套接字描述作为输入,然后让该构造函数调用setFd()
而不是socket()
。这将消除泄漏,然后复制构造函数可以在需要时获得此单个分配的套接字描述符的所有权。仅仅因为套接字变量未设置为无效\u socket
并不意味着从WinSock的角度来看套接字描述符是有效的。显然,它不是,否则WinSock不会正在抱怨。在您能够调用recv()
(客户端也会出现错误)之前,套接字已关闭
这是因为ServerSocket::accept()
正在按值返回新的ClientSocket
实例。编译器必须为返回值分配对象的第二个副本,但您的ClientSocket
类未定义任何副本构造函数。原始套接字描述符将从第一个ClientSocket
实例复制到第二个实例e、 然后,原始实例在退出时被释放,在第二个实例可以使用它之前关闭套接字。您需要定义一个副本构造函数,该构造函数拥有原始套接字描述符的所有权,并将原始实例的描述符设置为INVALID_socket
,以便其析构函数无法再关闭套接字
与此相关,您的ClientSocket
类存在句柄泄漏