2010-06-21 1 views
1

У меня есть простой сервер, который принимает клиентов. Клиент подключается к серверу. Первое, что сервер будет делать следующее:C++ winsock error

  1. захватить клиентский сокет
  2. создать поток для клиента
  3. вызов :: RECV();

проблема здесь заключается в том, что ПОЛУЧИТЬ returnes -1 WSAGetLastError returnes WSAENOTSOCK: (. Гнезда на nonsocket) Microsoft:. «Сделана попытка выполнить операцию на то, что не является сокет либо параметр дескриптор сокета не ссылается действительный сокет или для выбора, член fd_set недействителен. " я не могу понять, в чем проблема.

клиент имеет сокет все еще действующий, и любая ПРИЕМ доза клиент немедленно вернуть

Спасибо, Raxvan

+0

Если у вас возникли какие-либо шансы, вы можете отправить код примера? Это облегчило бы нам отлаживать. Думаю, что граб должен был «схватить»? –

+0

это самый простой сервер SOCKER s = :: accept (lsock, 0,0); Cient * c = new Клиент (ы); c-> RunThread(); // здесь будет создан и запущен поток – Raxvan

+0

Вы пытались сделать это без потоковой передачи на мгновение ... и если да, можете ли вы опубликовать рабочий пример? –

ответ

0

OK, это легко.

В своем коде, у вас есть

 inline sok Accept() 

, который возвращает sok по значению.

Здесь вы назначаете его в локальную переменную:

 sok client = listener.Accept(); 

и в конце этого выражения, временный sok вернулся из Accept() разрушается. Возможно, вы захотите установить контрольную точку или отладочную печать в sok::Close(), чтобы увидеть, что я имею в виду своими глазами.

+0

да, вы правы .... бог, я не понял этого, спасибо – Raxvan

0

According to MSDN, была проблема с сокетом.

Операция была предпринята для чего-то, что не является гнездом. Параметр дескриптора сокета не ссылался на действительный сокет, или для выбора член fd_set недействителен.

Как вы «сорвали» розетку - вы уверены, что это действительно? Попробуйте проверить доход от ::accept. Если возвращаемое значение == INVALID_SOCKET, то это ваша проблема. Вы можете позвонить WSAGetLastError, чтобы попытаться определить проблему.

+0

Да, это я вызываю WSAGetLastError сразу после принятия и ошибки нет. Возвращаемый сокет from accept() действителен – Raxvan

+0

Да, это допустимое значение, отличное от INVALID_SOCKET. принимать() дозу не подлежит никаким образом. – Raxvan

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 - это просто обертка вокруг сокета для чтения и письма – Raxvan

0

Просто убедитесь, что вы передаете ПРИЕМ() Функция правильные параметры, включая идентификатор Правильный сокета (что это «без знака Int» в любом случае!).

1

Я почти уверен, что вы сразу же закроете разъем вновь принятого соединения.

Вы используете класс sok, который автоматически закрывает гнездо на его древе (деструкторе).

sok client = listener.Accept(); 

Следующий код строит sok объекта из возвращаемого сокета. Его время жизни ограничено фигурными скобками петли while. Средство - сразу же после создания потока, который предполагается читать из сокета, вы закрываете его.

P.S. Вы неправильно используете sok. В соответствии с тем, что он делает, должен предотвратить создание более чем одного такого объекта для одного и того же сокета.

Например, копия c'tor должна быть объявлена ​​конфиденциальной. И это общедоступно в вашем коде. Также рекомендуется объявить c'tor, который принимает SOCKET с ключевым словом explicit.

Заключение: подумайте и рассмотрите использование вами класса sok.