C++ winsock 错误

Posted

技术标签:

【中文标题】C++ winsock 错误【英文标题】:C++ winsock error 【发布时间】:2010-06-21 12:34:45 【问题描述】:

我有一个接受客户端的简单服务器。 客户端连接到服务器。服务器首先会执行以下操作:

    获取客户端套接字 为客户端创建线程 调用 ::recv();

这里的问题是 recv 返回 -1 WSAGetLastError 返回 WSAENOTSOCK:(非套接字上的套接字操作。)Microsoft:“尝试对不是套接字的东西进行操作。套接字句柄参数未引用有效套接字,或者对于 select,fd_set 的成员无效。”我真的无法弄清楚问题到底是什么。

客户端的套接字仍然有效,客户端剂量的任何接收都会立即返回

谢谢,拉克斯万

【问题讨论】:

您有机会发布一些示例代码吗?这将使我们更容易调试。我猜 grub 应该是 'grab' 的? 是最基本的服务器 SOCKER s = ::accept(lsock,0,0);客户* c= 新客户; c->RunThread();//这里将创建并启动线程 你有没有试过在没有线程的情况下这样做......如果是这样,你能发布一个工作示例吗? 嗯....不,我现在就试试这个 在同一个线程 recv() 工作正常,它停止并等待数据。但是在客户端线程 recv() 将在第一次调用时失败。我检查了套接字,仍然是accept()返回的那个,例如(1839)返回的accept,并且客户端在套接字中具有相同的值 【参考方案1】:

我很确定您只是立即关闭新接受的连接的套接字。

您使用了sok 类,该类会在其d'tor(析构函数)处自动关闭套接字。

sok client = listener.Accept();

以下代码从返回的套接字构造sok 对象。它的生命周期受while 循环的花括号限制。 意味着 - 在创建应该从套接字读取的线程后立即关闭它。

附: 你滥用了sok。根据它在做什么,您必须防止为同一个套接字创建多个这样的对象。

例如,复制 c'tor 必须声明为私有。它在您的代码中是公开的。 此外,使用explicit 关键字声明接受 SOCKET 的 c'tor 也是一个好主意。

结论:思考并回顾您对sok 类的使用情况。

【讨论】:

【参考方案2】:

好的,这很容易。

在你的代码中,你有

        inline sok  Accept()

按值返回sok

在这里你将它分配给一个局部变量:

        sok client = listener.Accept();

在这个表达式的最后,从 Accept() 返回的临时 sok 被销毁。您可能想在sok::Close() 中放置一个断点或调试打印,以亲眼看看我的意思。

【讨论】:

【参考方案3】:

According to MSDN,socket有问题。

试图对不是套接字的东西进行操作。套接字句柄参数没有引用有效的套接字,或者对于 select,fd_set 的成员无效。

你是如何“grub”套接字的——你确定它是有效的吗?尝试检查来自::accept 的返回。如果返回值 == INVALID_SOCKET,那就是你的问题。届时您可以致电WSAGetLastError 尝试找出问题所在。

【讨论】:

是的,我在接受后调用 WSAGetLastError 并且没有错误。从accept()返回的socket是有效的 是的,它是一个有效值,不同于 INVALID_SOCKET。 accept() 不会以任何方式失败。【参考方案4】:
    void NetworkServer::RunServer()//main server loop
    
        while (flags & server_running)
        
            sok client = listener.Accept();
            if (listener && client.IsValid())
            
                if (clients.size >= MaxClients)
                
                    client.Close();
                    continue;
                
                ClientHandler* h = constructor->ConstructClient();
//ConstructClient() is just doing "new ClientHandler()";
                h->com_stream.forceConnected(client);
                h->id = client_ids.getId();
                h->flags = client_active;
                h->server = this;
                this->HandleNewConnection(h);//nothing..

                locker.Enter();
                clients.add(h);//add client to the client array
                h->threadRun();//stars the thread

                locker.Leave();
            
            else
            
                break;
            
        
    


    void tcpStream::forceConnected(sok& ss)
    
        server.socket = ss.socket;
        connected = true;
    



class sok
    
    private:
        SOCKET      socket;
    public:
        inline      sok()
            : socket(INVALID_SOCKET)
        
        
        inline      sok(SOCKET s)
            : socket(s)
        
        
        inline      sok(const sok & s)
            : socket(s.socket)
        
        
        inline      operator bool()const
        
            return (socket != INVALID_SOCKET);
        
        inline      ~sok()
        
            Close();
        
        inline bool IsValid()const
        
            return (socket != INVALID_SOCKET);
        
        inline void operator = (const sok & s)
        
            socket = s.socket;
        
    public:
        inline void Close()
        
            if (socket != INVALID_SOCKET)
            
                closesocket(socket);
                socket = INVALID_SOCKET;
            
        
        inline sok  Accept()
        
            return sok(::accept(socket, 0, 0));
        
        bool        tcpClient(NetAddress& adr);
        bool        tcpServer(wtf::ushort port, wtf::u32 clients = 10);
    private:
        friend class tcpStream;
    ;

uint tcpStream::read(void* out, const uint size)

    wtf::n32 r = ::recv(server.socket, (char*)out, size, 0);//this failes
    //int e = WSAGetLastError();
    connected = ((r) != (-1));
    return ((uint)r);/**/

【讨论】:

客户端中的com_stream成员是tcpStream类型。 tcpSteam 只是包裹在套接字周围进行读写【参考方案5】:

只要确保你向 recv() 函数传递了正确的参数,包括正确的套接字 id(无论如何它是一个“无符号整数”!)。

【讨论】:

以上是关于C++ winsock 错误的主要内容,如果未能解决你的问题,请参考以下文章

带有 winsock 和 std::thread 的 C++ 多线程服务器

MinGW 链接器错误:winsock

C++ WinSock2:连接()调用上的 WSA_INVALID_HANDLE

如何链接winsock.lib?

VC++ Winsock2 错误 10049。尝试构建 IRC 机器人

winsock 已弃用,没有警告