本文介绍了Winsock accept() 返回 WSAENOTSOCK(代码 10038)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

希望你今天过得愉快.另一个套接字问题,改天:)

我终于安装了 MicroSoft Visual C++ (MSVC++) IDE,加上 Platform SDK,所以我可以编译 winsock 应用程序了.

这里漏掉了一大块东西.在 ServerSocket::accept() 函数中,它创建了一个 ClientSocket 的新实例,并将它的套接字文件描述符设置为接受()ed 的那个,我也在那里检查过,它识别出描述符在那里也是有效的.

在我的 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) <<" " <<袜子<<结束;向量缓冲区(缓冲区大小+1,0);cout<<SocketRecv1:" <<(sockfd == INVALID_SOCKET) <<" " <<袜子<<结束;int ret = ::recv(sockfd, &buffer[0], bufsize, 0);cout<<SocketRecv2:" <<(sockfd == INVALID_SOCKET) <<" " <<袜子<<结束;//由于无效"套接字描述符,ret 显然是 -1,但是//以上语句在 (sockfd == INVALID_SOCKET) 上打印零(假)!:\如果 (ret 

附加信息:套接字处于阻塞模式,即尚未设置为非阻塞.我已经成功调用了 WSAStartup().这发生在服务器端,在从我的 ServerSocket::accept() 返回的 ClientSocket 实例上(是的,我也检查了那里的描述符 - 很好).客户端声明WSACONNRESET (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);

非常感谢!!!

解决方案

看起来您没有遵循 三规则.任何时候有析构函数时,都需要编写或禁用复制构造函数和赋值运算符.

在您的示例用法中:

ClientSocket 客户端 = server.accept();

变量 client 是从返回值复制构造的.然后析构函数在临时变量上运行,关闭套接字.

在 C++0x 中,您可以添加移动构造函数并解决此问题.现在,您应该实现 swap 并使用它:

ClientSocket 客户端;server.accept().swap(client);

或者通过client作为server.accept的参数:

ClientSocket 客户端;服务器.接受(客户端);

您可以按照 auto_ptr 的风格为 ClientSocket 编写移动复制构造函数,但我不建议这样做.人们不希望复制构造函数窃取资源.

hope you're having a good day. Another socket issue, another day :)

I finally got MicroSoft Visual C++ (MSVC++) IDE installed, plus the Platform SDK, so I can compile winsock applications.

Missed a chunk of stuff here. In the ServerSocket::accept() function, it creates a new instance of ClientSocket and sets it's socket file descriptor to the one that was accept()ed, I have also checked there and it's recognizing that the descriptor is valid there as well.

In my ClientSocket::recv() function, I call (obviously) the recv() function out of the winsock library. The issue I am having is that the socket descriptor I am using is being recognized by recv() as invalid, but only on the server-side ClientSocket instance returned from my ServerSocket::accept() - The client-side ClientSocket instance has no problems. I inserted multiple debug statements, the descriptor is valid.

The weirdest bit about this is that if I compile this exact same code with MinGW gcc/g++ on windows, it runs fine! It's only using MSVC++ that this problem occurs.

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];
}

Additional information: The socket is in blocking mode, i.e. has not been set to non-blocking. I have called WSAStartup() successfully. This is happening on the server side, on the ClientSocket instance returned from my ServerSocket::accept() (yes, I checked the descriptor there too - it's fine). The client side claims 'WSAECONNRESET (10054)' or 'WSAECONNABORTED (10053)'.

I can't think of anything else that could be wrong. The worst part is, it works fine using MinGW gcc/g++ on windows and linux both.

If you want to see the whole library, it's pasted at: (caution: 600+ lines!)
Socket.cxx - http://paste.pocoo.org/show/353725/
Socket.hxx - http://paste.pocoo.org/show/353726/

Thanks!!!

Update - As per Ben's solution, I am now using: void ServerSocket::accept(ClientSocket& sock);, and implementing as: ClientSocket mysock; server.accept(mysock);

Thank you so much!!!

解决方案

Looks like you're not following the Rule of Three. Any time you have a destructor, you need to write or disable both the copy-constructor and assignment operator.

In your example usage:

ClientSocket client = server.accept();

The variable client is copy-constructed from the return value. Then the destructor runs on the temporary variable, closing the socket.

In C++0x, you can add a move-constructor and cure this problem. For now, you should implement swap and use it:

ClientSocket client;
server.accept().swap(client);

Or pass client as a parameter of server.accept:

ClientSocket client;
server.accept(client);

You could write a moving copy-constructor for ClientSocket, in the style of auto_ptr, but I wouldn't recommend that. People don't expect a copy-constructor to steal resources.

这篇关于Winsock accept() 返回 WSAENOTSOCK(代码 10038)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-22 15:21