Title: WinSock connect() problem. Client thinks it is connected even when Server is down

As of right now, my program incorrectly displays the status of the connecting socket. Because of the if statements seen below, even when the server is down, my friends can access a part of the program which should only be available when successfully connected to the server.

On the client, they are accessing an input (which lets them send a message to the server) even when they are not connected to the server, where the program should have normally told them they failed to connect and would have closed the program.

Here is the code, can you help me fix up this if-statement so that it works properly?

//create the socket
        client = socket(AF_INET, SOCK_STREAM, 0);
	
	//set the socket I/O mode
	//if iMode = 0, blocking is enabled
	//if iMode != 0, non-blocking mode is enabled
	u_long iMode = 1;
	ioctlsocket(client, FIONBIO, &iMode); 

	//connect to the server
	if( connect( client, (sockaddr*)&server, sizeof(server) ) == SOCKET_ERROR)
	{
		if( WSAGetLastError() == WSAEWOULDBLOCK)
		{
			cout << "Attempting to connect.\n";
		}
		else
		{
			cout << "Failed to connect to server.\n";
			cout << "Error: " << WSAGetLastError() << endl;
			WSACleanup();
			system("pause");
			return 1;
		}
	}

To offer some help, the connect() SHOULD return WSAEWOULDBLOCK first, as it ATTEMPTS to connect. Eventually it will return 0 for success, or SOCKET_ERROR if it has failed. The error can be determined by the WSAGetLastError() function shown in the else block.
I can't seem to wrap my head around the logic required in order to setup the if-statements correctly after the first WSAEWOULDBLOCK check. Am I supposed to use select()? How do I do that? Thanks for the help!

Dani AI

Generated

What makes the client "think" it is connected is the test you run after connect on a nonblocking socket. As noticed, select can mark the socket writable even when the connect actually failed. The reliable pattern is: wait for writability, then query the pending error with getsockopt(SOL_SOCKET, SO_ERROR). Only a zero SO_ERROR means you are connected. Also, do not close the socket on the initial WSAEWOULDBLOCK as suggested by ; that aborts the in-flight connect. Close only on a final failure or timeout.

Here is the minimal loop you can drop in after connect returns WSAEWOULDBLOCK:

// s is nonblocking and connect() returned WSAEWOULDBLOCK
fd_set wfds, efds;
FD_ZERO(&wfds); FD_ZERO(&efds);
FD_SET(s, &wfds); FD_SET(s, &efds);

timeval tv{};
tv.tv_sec = 10;  // timeout seconds
int rc = select(0, nullptr, &wfds, &efds, &tv);
if (rc <= 0) {  // 0 = timeout, <0 = select error
    closesocket(s);
    // handle timeout/error
} else {
    int soerr = 0; int len = sizeof(soerr);
    getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&soerr, &len);
    if (soerr != 0) {
        WSASetLastError(soerr);
        closesocket(s);
        // handle connect failure (e.g., WSAECONNREFUSED/WSAETIMEDOUT)
    } else {
        // success; optionally return to blocking mode
        u_long mode = 0; ioctlsocket(s, FIONBIO, &mode);
    }
}

Two extra tips:

  • Gate your UI so the "send" path is unlocked only after the SO_ERROR == 0 check sets a connected=true.
  • If you need a simpler model, keep the socket blocking and implement a connect timeout with nonblocking+select just for the connection phase, then switch back.

For (works on LAN, not on Internet): ensure the server binds to 0.0.0.0 (not 127.0.0.1), forward the TCP port on your router to the server’s local IP, allow it through Windows Firewall, verify it is listening with netstat -ano, and test from outside your network (e.g., mobile hotspot) to avoid NAT hairpin issues.

Recommended Answers

All 4 Replies

Show your server socket code. If I'm right - you just forget to close server socket before shutting down the server.
And there are some errors in your client code. You forget to close socket after getting an error

//create the socket
        client = socket(AF_INET, SOCK_STREAM, 0);
	
	//set the socket I/O mode
	//if iMode = 0, blocking is enabled
	//if iMode != 0, non-blocking mode is enabled
	u_long iMode = 1;
	ioctlsocket(client, FIONBIO, &iMode); 

	//connect to the server
	if( connect( client, (sockaddr*)&server, sizeof(server) ) == SOCKET_ERROR)
	{
		if( WSAGetLastError() == WSAEWOULDBLOCK)
		{
			cout << "Attempting to connect.\n";
                                    closesocket(client);  //this 
		}
		else
		{
			cout << "Failed to connect to server.\n";
			cout << "Error: " << WSAGetLastError() << endl;
                                    closesocket(client); //and this
			WSACleanup();
			system("pause");
			return 1;
		}
	}

I hope it will help you.

Thanks for the help, but I know that is not the solution.

The client never connects to the server. The issue is that the client application will continue to the section that would be visible IF he was properly connected to the server.

I can't figure out how to setup the if statement so that it first passes the WSAEWOULDBLOCK check, and then properly checks to see if the connection has finished. Here is what MSDN says:

With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR, and WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are three possible scenarios:

* Use the select function to determine the completion of the connection request by checking to see if the socket is writeable.

//connect to the server
	iResult = connect(client, (sockaddr*)&server, sizeof(server));
	
	if(iResult == SOCKET_ERROR)
	{
		iError = WSAGetLastError();
		//check if error was WSAEWOULDBLOCK, where we'll wait
		if(iError == WSAEWOULDBLOCK)
		{
			cout << "Attempting to connect.\n";
			fd_set Write, Err;
			TIMEVAL Timeout;
			int TimeoutSec = 10; // timeout after 10 seconds

			FD_ZERO(&Write);
			FD_ZERO(&Err);
			FD_SET(client, &Write);
			FD_SET(client, &Err);

			Timeout.tv_sec = TimeoutSec;
			Timeout.tv_usec = 0;

			iResult = select(0,			//ignored
							 NULL,		//read
							 &Write,	//Write Check
							 &Err,		//Error Check
							 &Timeout);
			if(iResult == 0)
			{
				cout << "Connect Timeout (" << TimeoutSec << " Sec).\n";
				system("pause");
				return 1;
				
			}
			else
			{
				if(FD_ISSET(client, &Write))
				{
					cout << "Connected!\n";
				}
				if(FD_ISSET(client, &Err))
				{
					cout << "Select error.\n";
					system("pause");
					return 1;
				}
			}
		}
		else 
		{
			cout << "Failed to connect to server.\n";
			cout << "Error: " << WSAGetLastError() << endl;
			WSACleanup();
			system("pause");
			return 1;
		}
	}
	else
	{
		//connected without waiting (will never execute)
		cout << "Connected!\n";
	}

listen all I can connect and send messages at local but I can't connect in global. why? what should I do?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.