Click to See Complete Forum and Search --> : Winsock help needed NOW!


Guidosoft
January 20th, 2006, 05:32 PM
I need to find out if data is available to be read from a socket before I read it with recv so I don't have to wait cuz I am gona port my server over from VB to C++ and I'ma gona have a thread that loops through multiple sockets and reads the data and if all the other sockets have to wait for one to recieve data then that is gona suck balls.

So someone please help me to figure out how to retrieve if data is available from a socket.

Andreas Masur
January 20th, 2006, 05:44 PM
[ Redirected thread ]

Andreas Masur
January 20th, 2006, 05:45 PM
So someone please help me to figure out how to retrieve if data is available from a socket.
You can use 'select()' (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/select_2.asp) for example...

Guidosoft
January 20th, 2006, 05:54 PM
Can you please give me a code example and not just a link to MSDN?

I just need an example of how to find out if I can read data from the socket. I don't need all that other stuff that I already know in the example.

Andreas Masur
January 20th, 2006, 06:05 PM
Something like...

// Client send function
int Send(void *pvBuffer, int iStillToSend)
{
int iRC = 0;
int iSendStatus = 0;
timeval SendTimeout;
char *pBuffer = static_cast<char *>(pvBuffer);

fd_set fds;

FD_ZERO(&fds);
FD_SET(Socket, &fds);

// Set timeout
SendTimeout.tv_sec = 0;
SendTimeout.tv_usec = 250000; // 250 ms

// As long as we need to send bytes...
while(iStillToSend > 0)
{
iRC = select(0, NULL, &fds, NULL, &SendTimeout);

// Timeout
if(!iRC)
return -1;

// Error
if(iRC < 0)
return WSAGetLastError();

// Send some bytes
iSendStatus = send(Socket, pBuffer, iStillToSend, 0); // Socket is of type
// 'SOCKET' and is
// the current
// connection socket

// Error
if(iSendStatus < 0)
return WSAGetLastError();
else
{
// Update buffer and counter
iStillToSend -= iSendStatus;
pBuffer += iSendStatus;
}
}

return 0;
}

Guidosoft
January 20th, 2006, 06:56 PM
Thanx but I need to find out if there is data available to be read from a socket this way I don't have to wait for the function. I can just know if there isn't data, and don't run the recv function. I can make a simple loop to go through multiple sockets and recieve data in the same thread without having to wait on one socket that doesn't have any available data to read.

nkhambal
January 20th, 2006, 08:01 PM
you can used the same code in the previous post to check that if socket has anything to receive by modifying the select() call from


iRC = select(0, NULL, &fds, NULL, &SendTimeout);


to


iRC = select(0, &read_fds, &write_fds, NULL, &SendTimeout);


Where read_fds contains all the sockets to recv() from and write_fds contains all the sockets to send() to. You can add a single socket to both FD_SETS and then when select() returns, use FD_ISSET() to check which set (read or write) has the socket set. If its read set then you can run recv() on that socket to receive the data.

I think you need to read a bit on select() . Read the following link. It has an example too.

http://beej.us/guide/bgnet/output/html/advanced.html#select

heuristic
January 21st, 2006, 12:51 AM
Why dont you run the recv on a different thread? That thread will be blocked, but you can continue your work on the main thread.....

Guidosoft
January 21st, 2006, 07:40 AM
Oh so your saying I should have 500 threads for each socket?

That is retarded.


I have 2 threads in my application.
1. The GUI Thread - Handles all the GUI crap.
2. The server thread - Handles all the sockets.

I need to make sure that I don't have to wait on sockets. Thats why I am using select().

Andreas Masur
January 21st, 2006, 08:17 AM
Oh so your saying I should have 500 threads for each socket?

That is retarded.


I have 2 threads in my application.
1. The GUI Thread - Handles all the GUI crap.
2. The server thread - Handles all the sockets.

I need to make sure that I don't have to wait on sockets. Thats why I am using select().
Well...this raises another question...how many clients will connect to your server simultaneously? Usually, you don't want to handle them all in one thread but increase performance and scalability by using a multithreaded server...

Guidosoft
January 21st, 2006, 08:25 AM
500 maximum. Thats why I don't want to use 500 threads. My poor little system can't handle 500 threads.

O, and I have another problem.

When my server accepts a connection, it closes the listening socket and then redoes the listening process by creating, binding, and listening.

However it fails to bind and returns a WSAADDRINUSE error. I don't understand what is wrong. I closed the listening socket before I created a new one and bound it but it didn't bind I just get an error.

PLEASE HELP ME!!!!

PadexArt
January 21st, 2006, 09:58 AM
However it fails to bind and returns a WSAADDRINUSE error. I don't understand what is wrong. I closed the listening socket before I created a new one and bound it but it didn't bind I just get an error.

This is a problem related to the TCP stack implementation. For different reasons, a stack implementation can choose to keep the port reserved/locked for a while after it is closed. The safest solution would be to change your design so that you do not need to close it, reopen it and bind it every time.

Here is more information about the error you encounter:


Address already in use.
Typically, only one usage of each socket address (protocol/IP address/port) is permitted. This error occurs if an application attempts to bind a socket to an IP address/port that has already been used for an existing socket, or a socket that was not closed properly, or one that is still in the process of closing. For server applications that need to bind multiple sockets to the same port number, consider using setsockopt (SO_REUSEADDR). Client applications usually need not call bind at all— connect chooses an unused port automatically. When bind is called with a wildcard address (involving ADSDR_ANY), a WAEADDRINUSE error could be delayed until the specific address is committed. This could happen with a call to another function later, including connect, listen, WSAConnect, or WSAJoinLeaf.

Guidosoft
January 21st, 2006, 10:04 AM
OK, so I am only listening for 1 connections at a time. Now, after I accept,, how do I go back to listening on that port using the same listening socket? Hmm?

I shouldn't have to reconfigure the whole design because I have a functions RefreshLSock() which basically does the close, create, bind and listen. I should just be able to change that function to make it just listen again.

But how do I do that after accepting a connection?

And how come when I click Stop in my server and then Run, it works fine? The stop button closes all the sockets!

And what if I wanted to close, create, bind and listen each time? How would I go about unlocking and unreserving the port so I can?

Also, one more problem?

The select() function won't detect when telnet closes the connection or when any other client does it (I assume). How do I tell when the connection is closed because the function I made that uses select() woin't tell me and the function works flawlessly.

miteshpandey
January 21st, 2006, 10:37 AM
Hi Andreas,

I used code provided by you a long time back and have found a little bug.


// Client send function
int Send(void *pvBuffer, int iStillToSend)
{
int iRC = 0;
int iSendStatus = 0;
timeval SendTimeout;
char *pBuffer = static_cast<char *>(pvBuffer);

fd_set fds;

FD_ZERO(&fds);
FD_SET(Socket, &fds);

// Set timeout
SendTimeout.tv_sec = 0;
SendTimeout.tv_usec = 250000; // 250 ms

// As long as we need to send bytes...
while(iStillToSend > 0)
{
iRC = select(0, NULL, &fds, NULL, &SendTimeout);

// Timeout
if(!iRC)
return -1;

// Error
if(iRC < 0)
return WSAGetLastError();

// Send some bytes
iSendStatus = send(Socket, pBuffer, iStillToSend, 0); // Socket is of type
// 'SOCKET' and is
// the current
// connection socket

// Error
if(iSendStatus < 0)
return WSAGetLastError();
else
{
// Update buffer and counter
iStillToSend -= iSendStatus;
pBuffer += iSendStatus;
}
}

return 0;
}


This function FD_SET(Socket, &fds) should be used inside the while(iStillToSend > 0) before calling select.

If you don't do this the select will succeed the first time but then fail even if iStillToSend > 0 (excluding other possible reasons for failure)

Edit: I am not sure if FD_ZERO should also be inside the while....

runesvend
January 21st, 2006, 06:51 PM
OK, so I am only listening for 1 connections at a time. Now, after I accept,, how do I go back to listening on that port using the same listening socket? Hmm?The socket you specify in the listen() function will still listen for new incoming connection after a connection has been accepted with the accept() function. The socket descriptor returned by accept() is the socket connected to the client, while the socket descriptor passed as an argument in accept() is unaffected and will still be listening.

The backlog parameter of the listen() function determines the maximum number of connections that can be queued on the listening socket (ie. connections you haven't accepted) before it sends back WSAECONNREFUSED to the client trying to connect.