C++ winsock error
i have a simple server that accepts clients. The client connect to the server. The first thing the server will do the following:
- grab the client socket
- create a thread for client
- call ::recv();
the problem here is that recv returnes -1 WSAGetLastError returnes WSAENOTSOCK: (Socket operation on nonsocket.) Microsoft: "An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid." i 开发者_开发技巧can't really figure out what the problem really is.
the client has the socket still valid , and any recv the client dose will instantly return
Thanks, Raxvan
I'm pretty much sure that you just immediately close the socket of the newly accepted connection.
You make use of the sok
class, which closes the socket automatically at its d'tor (destructor).
sok client = listener.Accept();
The following code constructs the sok
object from the returned socket. Its lifetime is bounded by the curly braces of the while
loop.
Means - immediately after creating a thread that is supposed to read from the socket- you close it.
P.S.
You misuse the sok
. According to what it's doing you must prevent creation of more than one such an object for the same socket.
For instance the copy c'tor must be declared private. And it's public at your code.
Also it's a good idea to declare the c'tor that takes a SOCKET with explicit
keyword.
Conclusion: think and review your usage of sok
class.
OK, that's easy.
In your code, you have
inline sok Accept()
that returns a sok
by value.
Here you assign it to a local variable:
sok client = listener.Accept();
and at the end of this expression, the temporary sok
returned from Accept() gets destroyed. You might want to put a breakpoint or a debug print in sok::Close()
to see what I mean with your own eyes.
According to MSDN, there was a problem with the socket.
An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.
How did you 'grub' the socket - are you sure it's valid? Try checking the return from ::accept
. If the return value == INVALID_SOCKET, then that's your problem. You can call WSAGetLastError to try and identify the problem then.
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);/**/
}
Just make sure you pass the recv() function the correct parameters, INCLUDING the correct socket's id (it's an "unsigned int" anyway!).
精彩评论