Socket programming...

I want to make an Internet Cafe application used for distributing internet over several internet stations. The server is able to talk with clients an do many command based tasks. My question is:

What type of socket should have the server? More connecting sockets or a single accepting socket?

PS: I want to use SOCK_STREAM with AF_INET.
[354 byte] By [AndySoft] at [2007-11-17 11:50:11]
# 1 Re: Socket programming...
I'm not quite sure if I understood your question right but your assumption of using AF_INET + SOCK_STREAM is the way I would suggest as well.

Your server should be written as a multithreaded. That means that every incoming connections gets handled within a separate thread...

Ciao, Andreas

"Software is like sex, it's better when it's free." - Linus Torvalds
Andreas Masur at 2007-11-10 8:06:57 >
# 2 Re: Socket programming...
If you need to provide several workstations with access to internet from a single internet connection (CableModem, ASDL, raw internet link, whatever), you have a couple of solutions:

1. Proxy
2. Interent Connection Sharing
3. NAT/MASQUERADING

1. Proxy is an application connected to internet, ready to receive HTTP, FTP, SMTP, etc conections from the intranet, atend these connections acting like a bridge between local machines and remote servers.

2. Internet Connection Sharing: is a solution from Microsoft for small bussiness. You may connect a single worksattion to Internet and share its connection.

3. NAT: Network Address Translation: This is far the best solution, each workstation seems to be connected to internet.

--

Using SOCK_STREAM (TCP) you will be able to code a Proxy (not a NAT/MASQUERADING). Therefore you won't be able to provide UDP connections (audio/video streamings, most game networking, DNS resolution at local computer, etc)

You will have to listen on several ports of your intranet, to be able to receive HTTP, FTP, SMTP, POP, etc. Be carrefull with FTP 'cause it uses more that one connection (one for control and another one for data) and there are two method (passive and non-passive).

---------
_Leo_
http://www.drk.com.ar
_Leo_ at 2007-11-10 8:07:59 >
# 3 Re: Socket programming...
That is my problem.
If more then 4 or 5 messages are send at the same time to the server,
my server doesn't interpret all of them.
Few are lost forever.
It is very annoying.
My server must listen to 128 clients at the same time.
Should I create 128 accepting sockets,
each of them with his own thread?
My curent version uses 1 accepting socket. It can accept 128 connections.
For each connection I've created a thread containing Receive(), InterpretMessage(), and SendBackResult();
AndySoft at 2007-11-10 8:08:57 >
# 4 Re: Socket programming...
Your described approach is more than okay. One listening socket is enough to serve 128 clients. I never tested what happens if more than 5 clients connect to the server at the exact same time so I don't know if there exist some problems within the implementation of microsoft.

It looks like you are using the MFC socket stuff. I honestly don't have much experience with them since I always tried to avoid them. They add to much overhead to my mind and there are also memory leaks by using them. Therefore I always use the standard BSD sockets.

Nevertheless the client should be able to notice that the connections isn't working right and try to resend the message... There might be some milliseconds where the server is busy by switching one incoming connection to its own thread and would not listening during processing but the 'connect()' function will wait and retries so I really don't see any reason for losing messages.

Ciao, Andreas

"Software is like sex, it's better when it's free." - Linus Torvalds
Andreas Masur at 2007-11-10 8:09:53 >
# 5 Re: Socket programming...
Connecting function works OK. But the receiving function doesn't. If 1 accepting socket (socket binded to the local address and set to accept connecting sockets from distant addresses) has more then 4 or 5 threads set to receive data, not all of them are succeeding. Therefore I'm loosing important data. I'm using SOCKET class not CSocket class. SOCKET class is implemented in <windows.h> and uses Ws2_32.lib. Is this MFC?
How do I use BSD sockets in Windows? Is this possible?

Sorry for bothering you for so many times...
AndySoft at 2007-11-10 8:10:53 >
# 6 Re: Socket programming...
No it isn't MFC. 'SOCKET' is just a define not a class. Basically spoken you are using the standard BSD sockets already (I assume you are dealing with 'bind()', 'accept()', 'recv()' etc.). The necessary include file would be 'winsock2.h' for using winsock version 2. It will be also included within 'windows.h' but it is covered with an inclusion guard which will include 'winsock2.h' if the operating system is Windows NT or higher otherwise 'winsock.h' will be included (Winsock version 1.1). You can force the usage of 'winsock2.h' by including it first (it will automatically include 'windows.h') or by setting the appropriate flag like...

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif

Nevertheless then I don't see any reasons why it shouldn't work. Normally you have a root thread running which does the listening (via 'listen()'). When a new connection is coming in you accept it via 'accept()'. The connection gets a new socket (by the call to 'accept()'). You then start a newly thread using this new socket and do all the necessary thing like sending/receiving...

How does your send/receive functions look like. It is not guaranteed that one call to 'recv()' will get all the data...and maybe this is the problem...

Your send and receive functions should look like this (only client send function and server receive function)...

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

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

// As long 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;
}

// Server receive function
int ReceiveNBytes(SOCKET Socket, void *pvBuffer, int iStillToReceive)
{
int iRC = 0;
int iSendStatus = 0;
timeval ReceiveTimeout;
char *pBuffer = static_cast<char *>(pvBuffer);

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

fd_set fds;

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

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

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

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

// Receive some bytes
iReceiveStatus = recv(Socket, pBuffer, iStillToReceive, 0);

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

return 0;
}

Ciao, Andreas

"Software is like sex, it's better when it's free." - Linus Torvalds
Andreas Masur at 2007-11-10 8:12:03 >
# 7 Re: Socket programming...
Yes you are right. SOCKET is a define not a class. I was writing in a hurry. It seems to work. My original code is something like this:

class CAStation{
public:
SOCKADDR_IN *distant_address;
SOCKET *distant_sock;
.....
};
void CAStation::Accepting()
{
this->acceptHandle=CreateThread(NULL,0,&CAStation::AcceptProc,(CAStation *)this,0,&this->acceptID);
}

DWORD WINAPI CAStation::AcceptProc(void *p){
int len=sizeof(SOCKADDR);

CAStation *s;
s=(CAStation *)p;
s->next_sock=0;
for(int i=0;i<128;i++){
s->distant_address[i].sin_family=-1;
s->distant_sock[i]=(SOCKET)(-1);
}
listen(s->sock,18);
while(s->next_sock<128){
s->distant_sock[s->next_sock]=accept(s->sock,&(SOCKADDR &)s->distant_address[s->next_sock],&len);
s->next_sock++;
}
return 1;
}

void CAStation::ReceiveFrom(int FROM)
{
this->from=FROM;
CreateThread(NULL,0,&CAStation::RecvProc,(CAStation *)this,0,&this->recvID);
}

DWORD WINAPI CAStation::RecvProc(void *p)
{
int from;
DWORD err;
CAStation *s;
s=(CAStation *)p;
from=s->from;
err=0;
if(from<0||from>128)
return -1;
if(s->distant_address[from].sin_family==-1)
return -1;
while(err==0){
recv(s->distant_sock[from],s->stat_data[from].data,128,0);
err=GetLastError();
s->DoSomethingWithTheNewData();

}
return 1;
}
AndySoft at 2007-11-10 8:12:58 >
# 8 Re: Socket programming...
hi, i am writing an IRC client.. i was reading over this and the connection part i understand, but do you have a link to what commands are needed to actually log in to a channel?

i mean.. i've read the offical IRC protocol but i'm not sure which messages to send in order to allow my client to authenticate and join a room.

thanks!
phucket_20 at 2007-11-10 8:14:02 >