Jump to content
  • Advertisement
Sign in to follow this  
dave

A Winsock Question

This topic is 4839 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to write a server that can keep track of many clients. The idea is that i setup a socket to listen on, call Accept() which hangs until it receives a client connection. Then when it does recieve a connection i want to call recv and recv a custom packet from the client that states things like source ip, client name etc. I know that connections queue up and Accept() works its way through them one by one each tim you call it. I will have a map keeping track of the clients by their ip address. What i would like to know is if i want to maintain a connection with each client, do i have to go into multithreading my application? If i do, then is it possible for each thread to be in touch with the map that contains my client info. Obviously a client may disconnect and would need to be removed from the map. I am familiar with fork exec'ing in linux and thats a very easy thing to do, but what is the equivelent in windows? Thanks, ace

Share this post


Link to post
Share on other sites
Advertisement
Depends on how many clients you want to support and what you're trying to do. If each client connection doesn't need to share any state with other connections *or* the server itself and you're having a reasonable number of clients simultaneously connected (less than fifty, say) you could get away with a single thread per connection. One thread per client is horrible for scaling, but you need a pretty decent number of concurrent connections to actually see this in action.

Something like the echo protocol would be perfect for a single thread per socket. Each client gets back what it sends and clients don't know about other clients. On the other hand, a MUD server would be a bit more difficult - there'd be a lot of locking involved in the state that is shared between threads.

I'm partial to asynchronous communication when writing GUI programs. Look up WSAAsyncSelect(). Socket event notifications are sent into your Win32 message loop, giving you automatic synchronization. (Internally, Winsock makes a thread on your behalf and sends the UI thread messages.) Just watch out for WSAEWOULDBLOCK when you're doing socket operations.

Quote:
I am familiar with fork exec'ing in linux and thats a very easy thing to do, but what is the equivelent in windows?

fork()-ing creates a new process with a separate address space, which I don't think you want in this case. Look at using _beginthreadex() on Win32 to create a new thread.

Share this post


Link to post
Share on other sites
There is no need to do this with threads. If you want to keep it single-threaded(Believe me, single-thread is sooo much easier, no synchronization crap), take a look at select().

Select() will poke the socket to see if there is any received data on the socket. When there is data, it will return the number of bytes of data waiting on the socket.

This is a snippet out of my socket class:

int CSocket::HasData()
{
fd_set Input_set, Exc_set;
int s, nfds;
timeval timeout;

timeout.tv_sec = 0;
timeout.tv_usec = 0;

FD_ZERO(&Input_set);
FD_ZERO(&Exc_set);
FD_SET(m_Socket, &Input_set);
FD_SET(m_Socket, &Exc_set);

nfds = 1;

// Do the select
s = select(0, &Input_set, NULL, &Exc_set, &timeout);
if (s > 0)
{
if (FD_ISSET(m_Socket, &Exc_set))
return (SOCKET_ERROR);

if (FD_ISSET(m_Socket, &Input_set))
return (1);
}

return (s);
}



s will contain the number of bytes on the socket. Also, the first if() after the if (s > 0) is to check if the socket was closed from the other side. I noticed the sockets will tell you there is data, but that's just an echo. However, due to lack of comments, I forgot about the Input_set call.

Toolmaker

Share this post


Link to post
Share on other sites
Quote:
Original post by ace_lovegrove
I want to write a server that can keep track of many clients. The idea is that i setup a socket to listen on, call Accept() which hangs until it receives a client connection. Then when it does recieve a connection i want to call recv and recv a custom packet from the client that states things like source ip, client name etc.


Why use blocking sockets? Check if the listen socket is ready, then accept() as needed.

Why trust the client to give you its IP? The IP is set in accept():


int newfd;
int sinsize;
struct sockaddr_in insock;
string tmpaddr;

newfd=::accept(fd,(struct sockaddr *)&insock,(socklen_t *)&sinsize);
if (!newfd){
// Error.
// Report it.
return;
}
tmpaddr=inet_ntoa(insock.sin_addr);


Quote:

I know that connections queue up and Accept() works its way through them one by one each tim you call it. I will have a map keeping track of the clients by their ip address.

I'd use their file descriptors [sockets] to allow multiple client from one IP [since mulitple legitimate users might be tunnelling through one host]
Quote:


What i would like to know is if i want to maintain a connection with each client, do i have to go into multithreading my application?


No, accept creates a connection that will stay until disconnected, multithreading or not. More to your question, no; you could use select() instead.
Quote:

If i do, then is it possible for each thread to be in touch with the map that contains my client info. Obviously a client may disconnect and would need to be removed from the map.


Probably, I don't know much about multithreading.
Quote:

I am familiar with fork exec'ing in linux and thats a very easy thing to do, but what is the equivelent in windows?

Thanks,

ace


IIRC fork() is a posix call, and should be similarly portable to windows. That said, simply spawning a new thread is a more windows way of doing it. Either way, I prefer using select(), since after you figure it out it's fairly easy to keep using.

Share this post


Link to post
Share on other sites
Ok, so i understand that if i want to poll a selection of sockets for input pending i use select(). But how do i do this at the same time as waiting to accept new connections using accept(). Since accept() is blocking, right?

ace

Share this post


Link to post
Share on other sites
Quote:
Original post by ace_lovegrove
Ok, so i understand that if i want to poll a selection of sockets for input pending i use select(). But how do i do this at the same time as waiting to accept new connections using accept(). Since accept() is blocking, right?

ace


True.

Essentially, if select() tells you that the listening socket is ready for reading, call accept(). It will be guaranteed to work [and not block]. If the listening socket is -not- ready to be read, do not call accept(), since there's no pending connections.

Share this post


Link to post
Share on other sites
Ah ok, i misunderstood a bit. I thought that select() monitored for incoming data on the sockets that were authorised by accept().

Thanks guys,

ace

Share this post


Link to post
Share on other sites
One last little question.

I have a sockaddr_in struct filled out by accept for a connection. How can i get the ip address and host name from that information?

If im not on the right track then how do i get this information from a client?

ace

Share this post


Link to post
Share on other sites
Quote:
Original post by ace_lovegrove
One last little question.

I have a sockaddr_in struct filled out by accept for a connection. How can i get the ip address and host name from that information?

If im not on the right track then how do i get this information from a client?

ace


The IP address can be gotten like I did in the code snippet above. After that snippet, the std::string tmpaddr contains the xxx.xxx.xxx.xxx ip of the connecting machine.

The host name is less uniform. You'll need the client to provide it, or do a reverse DNS lookup of the IP to get the DNS name of the host [if one exists]. Host names aren't terribly reliable, and generally differ from OS to OS.

Share this post


Link to post
Share on other sites
I don't know much about winsock, but how long would an accept call take if you know someone is trying to connect? If it takes anything more than an ms or two to complete wouldn't it bog the entire server in a singe-threaded environment?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!