希望您过得愉快。另一个套接字问题,改天:)
我终于安装了MicroSoft Visual C ++(MSVC ++)IDE,以及Platform SDK,以便可以编译winsock应用程序。
在这里错过了很多东西。在ServerSocket :: accept()函数中,它创建一个ClientSocket的新实例,并将其套接字文件描述符设置为accept()的套接字文件描述符,我也在此处进行了检查,并且它也知道该描述符在此处也是有效的。
在我的ClientSocket :: recv()函数中,我(显然)从winsock库中调用recv()函数。我遇到的问题是recv()将我使用的套接字描述符识别为无效,但仅在从我的ServerSocket :: accept()返回的服务器端ClientSocket实例上-客户端ClientSocket实例没有问题。我插入了多个调试语句,该描述符有效。
最奇怪的一点是,如果我在Windows上用MinGW gcc / g ++编译完全相同的代码,它运行得很好!仅使用MSVC ++会出现此问题。
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];
}
附加信息:套接字处于阻止模式,即尚未设置为非阻止。我已经成功调用了WSAStartup()。这是在服务器端发生的,在从我的ServerSocket :: accept()返回的ClientSocket实例上(是的,我也在那儿检查了描述符-很好)。客户端要求“ WSAECONNRESET(10054)”或“ WSAECONNABORTED(10053)”。
我想不出其他任何可能出错的地方。最糟糕的是,在Windows和linux上使用MinGW gcc / g ++都可以正常工作。
如果要查看整个库,请将其粘贴在:(警告:超过600行!)
Socket.cxx-http://paste.pocoo.org/show/353725/
Socket.hxx-http://paste.pocoo.org/show/353726/
谢谢!!!
更新-根据Ben的解决方案,我现在使用:
void ServerSocket::accept(ClientSocket& sock);
,并实现为:ClientSocket mysock; server.accept(mysock);
非常感谢!!!
最佳答案
看起来您没有遵循Rule of Three。每当有析构函数时,都需要编写或禁用复制构造函数和赋值运算符。
在您的示例用法中:
ClientSocket client = server.accept();
变量
client
是从返回值复制构造的。然后,析构函数在临时变量上运行,关闭套接字。在C ++ 0x中,可以添加一个移动构造函数并解决此问题。现在,您应该实现
swap
并使用它:ClientSocket client;
server.accept().swap(client);
或将
client
作为server.accept
的参数传递:ClientSocket client;
server.accept(client);
您可以按照
ClientSocket
的样式为auto_ptr
写一个移动拷贝构造函数,但是我不建议这样做。人们不希望复制构造函数会窃取资源。