Click here to Skip to main content
15,035,283 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have inherited some code that I am trying to understand and get working. I'm learning about sockets as I go. The method I am having problems with is one that calles the 'select' method. It fail and returns the error: WSAENOTSOCK. Could anyone possibly tell me what might be causing this. I have really struggled to anything that helps me with this.

The variable m_listeningSocket has been defined as an int and is the return value from socket:
int m_listeningSocket = socket(AF_INET, SOCK_STREAM, 0);

although I don't understand why this return value has been set to an int as I thought it should be a SOCKET type - is this going to cause problems.


int Select( int timeout)
{
  struct timeval timout;
  int    ret, maxfdp1;

  if( timeout <= 0 ) 
	  return -1;
  /* setup sockets to read */
  maxfdp1 = m_listeningSocket + 1;
 
  FD_ZERO( &m_rset );
  FD_SET ( m_listeningSocket, &m_rset );
  FD_SET ( 0, &m_rset );		// this adds stdin to the set
  FD_ZERO( &m_wset );
  FD_ZERO( &m_eset );

  timout.tv_sec  = timeout / 1000;
  timout.tv_usec = timeout % 1000;

  ret = ::select( maxfdp1, &m_rset, &m_wset, &m_eset, &timout );
  
  return ret;
}



'getsockopt' returns zero, indicating that there is no problem, and the rest of the code that sets the socket up before I call the Select method is:
int CCCD_Socket::CreateListenSock()
{
	int retVal = -1;

	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(1, 1);
	int err = WSAStartup(wVersionRequested, &wsaData);

	if(err != 0)
	{
		printf("WSAStartup error %ld", WSAGetLastError());
		WSACleanup();
		return retVal;
	}

	struct sockaddr_in channel;
	memset(&channel, 0, sizeof(channel)); //zero channel
	channel.sin_family = AF_INET; 
	channel.sin_addr.s_addr = htonl(INADDR_ANY);//can use any interface for the defined port - should be ok if only one device wants to connect to the port
	channel.sin_port = htons(SERVER_PORT);

	m_listeningSocket = socket(AF_INET, SOCK_STREAM, 0);//0 = prototcol i snot defined, i think IPPROTO_TCP is default
	if(m_listeningSocket == -1)
	{
		printf("socket error %ld", WSAGetLastError());
		WSACleanup();
		return retVal;
	}

	//not sure if this is necessary
	int on = 1;
	setsockopt(m_listeningSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));

	int b = bind(m_listeningSocket, (struct sockaddr*)&channel, sizeof(channel));
	if(b < 0)
	{
		printf("bind error %ld", WSAGetLastError());
		WSACleanup();
		return retVal;
	}

	int l = listen(m_listeningSocket, 10); 
	if(l < 0)
	{
		printf("listen error %ld", WSAGetLastError());
		WSACleanup();
		return retVal;
	}
	else
	{
		retVal = m_listeningSocket;
	}
	return retVal;
}
Posted
Updated 17-Feb-12 5:53am
v2

I would try to take out stdin from the set and see if that makes a difference. IIRC, that's a difference between Winsock and Berkeley sockets.

You find the Winsock select() documentation here
   
Comments
Jackie Lloyd 17-Feb-12 15:44pm
   
OK, thankyou. I guess that is there because the original code was written for linux and I am trying to convert it to windows?
Jackie Lloyd 18-Feb-12 17:32pm
   
Thankyou very much - that solved the problem. I am now wondering if there is a windows equivalent to add stdin to the listening sockets that are monitored for input? I guess this would be necessary to check for keyboard input - is this correct?
bjorn_ht 19-Feb-12 15:12pm
   
I don't know if there is a windows equivalent to linux/unix select(). It could be you can make WaitForMultipleObjects or WSAWaitForMultipleObjects work.

Another option is to move the server logic to a background thread and only leave the console i/o in the main thread. That way you don't have to change the current server logic with the select() call, and you can just let the console i/o calls block since nothing else goes on in that thread.
Jackie Lloyd 19-Feb-12 15:35pm
   
Thank you for your suggestions - I will have a go :)
bjorn_ht 20-Feb-12 14:21pm
   
Good luck!
I don't think the listening socket is intended to be used in a select function.

Use the accept() function on the listening socket to see if you have a new incoming connection. The accept() function will return a newly conencted socket if a new connection request is pending.

Use the sockets you get from accept() in your select statement.
   
Comments
Jackie Lloyd 17-Feb-12 15:10pm
   
Hi, very many thanks for your suggestion. Unfortunately, I don't think that is the case. This example http://tangentsoft.net/wskfaq/examples/basics/select-server.html uses the listening socket in the select method.
JackDingler 17-Feb-12 15:23pm
   
Good example. So how is your code different than the code in the example?
Jackie Lloyd 17-Feb-12 15:38pm
   
Yes, I wish I had found the example earlier today, although I did hunt high and low - typical. There seems to be a difference in the FD_SET part. And the return value from socket is defined as an int in my code rather than a SOCKET - is that because the code I am starting with was written for linux. My job is to port it to windows :-(.
That code really doesn't look right.

select in this form takes an array of "sockets" and checks for read / write data availability (http://support.sas.com/documentation/onlinedoc/sasc/doc750/html/lr2/select.htm[^])

The first argument appears to be the size of the table of entries initialized by "FD_SET()" calls yet you pass it the SOCKET returned by Microsoft and add one to it.

maxfdp1 = m_listeningSocket + 1;

If that ever worked in the past, I suspect it was totally by accident. Microsoft sockets might return any 32 bit value as a result, not some nice number like "1", as the SOCKET variable.

I personally do not use these API for my socket programs so I'm only commenting on the pecularity of using "m_listeningSocket + 1" as a "size" parameter. Seems too much like "magic" to me.
   
Comments
Jackie Lloyd 17-Feb-12 15:47pm
   
Thanks for that, it seemed odd to me too. I was given this code written for linux and told to convert it to windows. But I am not able to see the linux version working. The documentation you have referred me to is for unix, so I guess that means that I need to use a version that works with winsock.
Chuck O'Toole 17-Feb-12 15:55pm
   
Well, even for Linux the example attached to that documentation seems odd. It does

FD_ZERO(&fds);
FD_SET(s1, &fds);
FD_SET(s2, &fds);
rc = select(sizeof(fds)*8, &fds, NULL, NULL, &timeout);

So it sets two arguments into the fds structure and then uses sizeof() and multiplies that by a magic constant 8 as the size argument for select(). It still seems like it relies on some underlying magic if multiplying by 8 after adding 2 arguments is the right thing to do. Personally, I don't think this is very clear documentation at all.
Chuck O'Toole 17-Feb-12 16:03pm
   
Another point (or two). Note that the Microsoft documentation says that it ignores the first parameter as it is only for compatibility with Berkley sockets so that issue is off the list. Note that there is a comment in your code that says
FD_SET ( 0, &m_rset ); // this adds stdin to the set
implying that "stdin" is OK to add to "select()" yet the error you get is "NOT A SOCKET". stdin is definitely not a socket so it might be that it is complaining about. More magic numbes, "0" appears to mean "stdin" for Linux. Maybe Windows is not happy about that.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900