C++ winsock错误

问题描述:

我有一个接受客户端的简单服务器。 客户端连接到服务器。服务器将执行以下操作的第一件事:C++ winsock错误

  1. 抢客户socket
  2. 创建一个线程为客户
  3. 电话::的recv();

这里的问题是,recv的returnes -1 WSAGetLastError returnes WSAENOTSOCK:(。上nonsocket插座操作)微软:“一个操作尝试的东西,不是一个套接字无论是套接字句柄参数没有引用一个有效的套接字,或者select,fd_set的成员无效。“我无法弄清楚问题究竟在哪里。

客户有插座仍然有效,任何recv的客户量会立即返回

感谢,Raxvan

+0

任何机会,你可以张贴一些示例代码?这会让我们更容易进行调试。我猜grub应该是'抢'? – 2010-06-21 12:43:26

+0

它是最基本的服务器 SOCKER s = :: accept(lsock,0,0); Cient * c =新客户; C-> RunThread(); //这里的线程将被创建并启动 – Raxvan 2010-06-21 12:45:32

+0

您是否尝试过这样做没有穿了一会儿......如果是这样,你可以发布工作的例子吗? – 2010-06-21 12:52:09

好吧,那很简单。

在代码中,你有

 inline sok Accept() 

按值返回sok

在这里,您将其分配到一个局部变量:

 sok client = listener.Accept(); 

,并在此表达的结束,从接受返回临时sok()被销毁。您可能需要在sok::Close()中放置断点或调试打印以查看我的意思。

+0

是啊,你是正确的....上帝,我想通diden't说出来,谢谢 – Raxvan 2010-06-21 18:37:55

According to MSDN,有一个与插座有问题。

一个操作尝试在不是套接字的东西上。套接字句柄参数没有引用有效的套接字,或者对于select,fd_set的成员无效。

你是怎么'grub'的插口 - 你确定它是有效的吗?尝试检查从::accept返回。如果返回值== INVALID_SOCKET,那就是你的问题。您可以致电WSAGetLastError尝试并确定问题。

+0

是啊,这就是我所说WSAGetLastError只是接受后并没有错误。 accept()返回的套接字有效 – Raxvan 2010-06-21 12:46:52

+0

yes是一个有效值,与INVALID_SOCKET不同。 accept()不会以任何方式失败。 – Raxvan 2010-06-21 12:52:39

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);/**/ 
} 
+0

客户端中的成员com_stream是tcpStream类型的。 tcpSteam只是wrappe插座周围读写 – Raxvan 2010-06-21 13:23:48

只要确保您通过recv()函数正确的参数,包括正确的套接字的ID(无论如何这是一个“无符号整数”)。

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

您可以使用sok类,该类在其终端(析构函数)处自动关闭套接字。

sok client = listener.Accept(); 

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

P.S. 您误用sok。根据它在做什么必须防止为同一套接字创建多个这样的对象。

例如复制c'tor必须声明为私人。它在您的代码中公开。 另外它是一个好主意,宣布c'tor需要与explicit关键字SOCKET。

结论:考虑并检查您的sok类的用法。