Winsock accept () returns WSAENOTSOCK (code 10038)

hope you have a nice day. Another socket problem, another day :)

Finally, I got the installed MicroSoft Visual C ++ environment (MSVC ++), as well as the platform SDK, so I can compile winsock applications.

Missed a piece of stuff here. In the ServerSocket :: accept () function, it creates a new ClientSocket instance and sets its socket file descriptor to the one that was accept () ed, I also checked there, and it recognized that the descriptor is really there.

In my ClientSocket :: recv () function, I call (obviously) the recv () function from the winsock library. The problem I'm facing is that the socket descriptor I'm using is recognized by recv () as invalid, but only on the ClientSocket instance on the server side returned from my ServerSocket :: accept (). There is no problem on the client instance of ClientSocket. I inserted some debug statements, the handle is valid.

The strangest bit about this is that if I compile this exact code using MinGW gcc / g ++ on windows, it works fine! It uses only MSVC ++ that this problem occurs.

string ClientSocket::recv(int bufsize) { if (!isConnected()) throw SocketException("Not connected."); cout << "SocketRecv: " << (sockfd == INVALID_SOCKET) << " " << sockfd << endl; vector<char> buffer(bufsize+1, 0); cout << "SocketRecv1: " << (sockfd == INVALID_SOCKET) << " " << sockfd << endl; int ret = ::recv(sockfd, &buffer[0], bufsize, 0); cout << "SocketRecv2: " << (sockfd == INVALID_SOCKET) << " " << sockfd << endl; // ret is apparently -1 because of "invalid" socket descriptor, but the // above statements print zero (false) on the (sockfd == INVALID_SOCKET) ! :\ if (ret < 0) { #ifdef _WIN32 switch((ret = WSAGetLastError())) { #else switch(errno) { #endif case DECONNREFUSED: // The 'd' prefix means _I_ defined it, ie from windows it's // set to 'WSAECONNREFUSED', but from linux it set to 'ECONNREFUSED' throw SocketException("Connection refused on recover."); break; case DENOTCONN: throw SocketException("Not connected."); break; case DECONNABORTED: throw SocketException("Software caused connection abort."); break; case DECONNRESET: throw SocketException("Connection reset by peer."); break; default: //usually this itoa() and char/string stuff isn't here... needed it in //order to find out what the heck the problem was. char tmp[21]; string tmp4 = "Unknown error reading socket. "; string tmp3 = tmp4 + itoa(ret, tmp, 10); //this throw keeps throwing "Unknown error reading socket. 10038" throw SocketException(tmp3); break; } } else if (ret == 0) { connected = false; return ""; } return &buffer[0]; } 

Additional information: The socket is in blocking mode, i.e. was not set to non-blocking. I have successfully called WSAStartup (). This happens on the server side, in the ClientSocket instance returned from my ServerSocket :: accept () (yes, I also checked the handle there - that's fine). The client side declares: "WSAECONNRESET (10054)" or "WSAECONNABORTED (10053)."

I can't think of anything else that could be wrong. Worst of all, it works great using MinGW gcc / g ++ for Windows and Linux.

If you want to see the entire library, it is inserted in: (caution: 600+ lines!)
Socket.cxx - http://paste.pocoo.org/show/353725/
Socket.hxx - http://paste.pocoo.org/show/353726/

Thanks!!!

Update . According to the solution for Ben, I now use: void ServerSocket::accept(ClientSocket& sock); and implement as: ClientSocket mysock; server.accept(mysock); ClientSocket mysock; server.accept(mysock);

Thank you very much.

0
c ++ visual-c ++ sockets winsock
source share
2 answers

It looks like you are not following Rule of Three . Every time you have a destructor, you need to write or disable both the copy operator and the assignment operator.

In your usage example:

 ClientSocket client = server.accept(); 

The client variable is copied from the return value. Then the destructor runs in a temporary variable, closing the socket.

In C ++ 0x, you can add a move constructor and cure this problem. For now, you should implement swap and use it:

 ClientSocket client; server.accept().swap(client); 

Or pass client as the server.accept parameter:

 ClientSocket client; server.accept(client); 

You can write a moving instance constructor for ClientSocket in the auto_ptr style, but I would not recommend this. People do not expect copy constructor to steal resources.

+4
source share

Just because your socket variable is not set to INVALID_SOCKET does not mean that the socket handle is valid from the point of view of WinSock. Obviously, this is not so, otherwise WinSock will not complain about it. The socket closes before you can call recv() (which is also visible on the client side, receiving errors).

The main reason for this is that ServerSocket::accept() returns a new ClientSocket instance by value. The compiler should allocate a second copy of the object for the return value, but your ClientSocket class ClientSocket not define a copy constructor. The initial descriptor descriptor will be copied from the first instance of the ClientSocket to the second instance, then the original instance will be released after exiting, closing the socket before the second instance can use it. You need to define a copy constructor that takes responsibility for the original socket descriptor and sets the original instance descriptor to INVALID_SOCKET so that its destructor can no longer close the socket.

In this regard, your ClientSocket class has a handle leak in it. You call WSAStartup() and socket() inside the ClientSocket constructor (which is not the best place for any of these calls). When ServerSocket::accept() accepts a new client, you call ClientSocket::setFd() with a new socket descriptor that replaces the original socket descriptor that was allocated in the ClientSocket constructor without freeing it up correctly. You must define a second ClientSocket constructor that accepts the existing socket description as input, and then this constructor calls setFd() instead of socket() . This will eliminate the leak, and then the copy constructor can take responsibility for this separate descriptor descriptor if necessary.

0
source share

All Articles