Question about FD_WRITE

Started by
4 comments, last by hplus0603 10 years, 7 months ago

Hi, im aving trouble finding a bug in my program, then it suddently hit me, im not handling the FD_WRITE event in my code. What happen if you send data and the buffer is full? Could that be the cause of my problem?

If so, how should i handle this? What i though is to set a bool variable to true whenever i receive an FD_WRITE event, then set it to false when i receive WSAEWOULDBLOCK, and only send when the variable is true. Is that right?

thx

Advertisement

Assuming you're asking about the socket API, on most system send() blocks until data can be written if in blocking mode, but if in non-blocking mode it returns an error. An exception is if the message is too large for the underlying protocol in which it would return a different error.

Yea, im using winsock sockets in c++, with WSAAsyncSelect, so im using the windows message system to do my stuff, my socket are not blocking.

It is totally possible for send() to return less than the full amount of data requested to send.

This is why you typically will want to have a queue of outgoing data, and send from this queue, and only dequeue the data that actually was sent, keeping the rest for the next time around.

Also, public service announcement: WSAAsyncSelect() is a very old API, performs very poorly, has known implementation bugs (that Microsoft retains for compatibility reasons,) and is not portable at all. I recommend nobody use it.

enum Bool { True, False, FileNotFound };

It is totally possible for send() to return less than the full amount of data requested to send.

Yea, that part i am aware of it. It's handled properly.


This is why you typically will want to have a queue of outgoing data, and send from this queue, and only dequeue the data that actually was sent, keeping the rest for the next time around.

That's actually not a bad idea. I was sending my data by chunks in a loop, so that's might be my problem here. Although im not sure it would help much, gotta think about it.

I need to send my data as fast as possible.


Also, public service announcement: WSAAsyncSelect() is a very old API, performs very poorly, has known implementation bugs (that Microsoft retains for compatibility reasons,) and is not portable at all. I recommend nobody use it.

That part i don't understand. I tried polling the socket with select() in my previous version of my projects, and it's seem that each time i called it, it costed me about 1-15 ms,

so that's why i used WSAAsyncSelect(), and it seem to be a lot faster this way... until it crash for no reason, probably because of the FD_WRITE message i forgot to handle.

It also make servers that handle multiples connections much easier to deal with, and require no threads to work, althrough now i think im gonna need one to write.

And i can't use blocking sockets, because it could hang my program indefinitely.

So, i don't have much other options.

Also, portability is not an issue here, im only targeting windows machines.

EDIT: That's the old code i was using to poll the socket, specifically, my CanRead() function: (CanWrite() was pretty much identical)


//-----------------------------------------------------------------------------
// Name : CanRead()
// Desc : Tell if we are ready to read data
//-----------------------------------------------------------------------------
bool CNetBaseEngine::CanRead()
{
	// Setup the timeout for the select() call
	timeval waitd;
	waitd.tv_sec  = 0; // Make select wait up to 1 second for data
	waitd.tv_usec = 1; // and 0 milliseconds.

	// Zero the flags ready for using
	fd_set read_flags;
	FD_ZERO(&read_flags);
	
	// Set the read flag to check the write status of the socket
	FD_SET(m_Socket, &read_flags);

	// Now call select
	int Res = select(m_Socket, &read_flags,(fd_set*)0,(fd_set*)0,&waitd);
	if(Res < 0) {  // If select breaks then pause for 5 seconds
		//Sleep(3);  // then continue
		// Socket not ready to read
		return false;
	}

	// If we are ready to read...
	if(FD_ISSET(m_Socket, &read_flags)){
		// Clear the read flag
		FD_CLR(m_Socket, &read_flags);
		// Socket is ready to read
		return true;
	} else {
		// Socket not ready to read
		return false;
	}
}

The problem is, if i used waitd.tv_usec = 0; i would get errors in my program...

If you want high performance sockets on Windows, you want to use I/O completion ports with OVERLAPPED I/O.

If you want a nice, portable wrapper on top of this (that uses equally efficient implementations on Linux) then look at boost::asio.

Btw: I would be highly surprised if calling select() with a zero timeout would take 1 ms.

enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement