2010-06-21 103 views
1

我有一個接受客戶端的簡單服務器。 客戶端連接到服務器。服務器將執行以下操作的第一件事: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

回答

0

好吧,那很簡單。

在代碼中,你有

 inline sok Accept() 

按值返回sok

在這裏,您將其分配到一個局部變量:

 sok client = listener.Accept(); 

,並在此表達的結束,從接受返回臨時sok()被銷燬。您可能需要在sok::Close()中放置斷點或調試打印以查看我的意思。

+0

是啊,你是正確的....上帝,我想通diden't說出來,謝謝 – Raxvan 2010-06-21 18:37:55

0

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

0
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

0

只要確保您通過recv()函數正確的參數,包括正確的套接字的ID(無論如何這是一個「無符號整數」)。

1

我很肯定你只是立即關閉新接受的連接的套接字。

您可以使用sok類,該類在其終端(析構函數)處自動關閉套接字。

sok client = listener.Accept(); 

以下代碼從返回的套接字構造sok對象。它的生命週期由while循環的花括號限制。 意味着 - 創建一個應該從套接字讀取的線程後立即關閉它。

P.S. 您誤用sok。根據它在做什麼必須防止爲同一套接字創建多個這樣的對象。

例如複製c'tor必須聲明爲私人。它在您的代碼中公開。 另外它是一個好主意,宣佈c'tor需要與explicit關鍵字SOCKET。

結論:考慮並檢查您的sok類的用法。