what is the backlog in the int listen (SOCKET s, int backlog); function good for
Quoted directly from MSDN:
<b>listen[/b}
The listen function places a socket in a state in which it is listening for an incoming connection.
int listen(
SOCKET s,
int backlog
);
Parameters
s
[in] Descriptor identifying a bound, unconnected socket.
backlog
[in] Maximum length of the queue of pending connections. If set to SOMAXCONN, the underlying service provider responsible for socket s will set the backlog to a maximum reasonable value. There is no standard provision to obtain the actual backlog value.
So the answer is that it's the size of the pending connections queue...
When you create a socket, and put it to listen, you need to specify the amount of connection you want to handle. I believe Linux refuses new connections.
so if i want a server where 32 clients can connect at max i'll use 32 ?
Yep
and it just set the socket in the listen mode or does it wait until 32 clients have connected?
No, it sets the socket in listen mode. You then call accept to get incoming calls. Usually, you do a while like:
listen(oldsocket, 32); while ((newsocket = accept(oldsocket, ...)) > 0) { process_new_client(newsocket); ... }
That piece of code is blocking
[edited]
and accept is a blocking function... how can i stop it
listen returns immediately. accept is the one which blocks the socket until a client connects. You can use fnctl (Linux for sure... maybe Windows has it too?) to declare the socket as non blocking, or use select to simulate the non-blocking stuff.
and the send and receive functions a re also blocking ones.
can i implement checking once for a package to receive with select too or how should this be done?
Yes, you can use select to multiplex a program. Select has five parameters, the first one is the maximun descriptor plus one of socket to check, the second parameter is a bag (fd_set) with sockets to check for incoming information (receive data), the third parameter is a bag for outcoming information (send data), the fourth is a bag with sockets for exceptions, and the last parameter is the timeout select should wait before stopping checking the sockets. So, you can set sockets to listen into the second bag, and whenever one is set, you receive the information. This is the example in Linux:
| 1 | #include <stdio.h> |
| 2 | #include <sys/time.h> |
| 3 | #include <sys/types.h> |
| 4 | #include <unistd.h> |
| 5 | |
| 6 | int |
| 7 | main(void) { |
| 8 | fd_set rfds; |
| 9 | struct timeval tv; |
| 10 | int retval; |
| 11 | |
| 12 | /* Watch stdin (fd 0) to see when it has input. */ |
| 13 | FD_ZERO(&rfds); |
| 14 | FD_SET(0, &rfds); |
| 15 | /* Wait up to five seconds. */ |
| 16 | tv.tv_sec = 5; |
| 17 | tv.tv_usec = 0; |
| 18 | |
| 19 | retval = select(1, &rfds, NULL, NULL, &tv); |
| 20 | /* Don't rely on the value of tv now! */ |
| 21 | |
| 22 | if (retval) |
| 23 | printf("Data is available now.\n"); |
| 24 | /* FD_ISSET(0, &rfds) will be true. */ |
| 25 | else |
| 26 | printf("No data within five seconds.\n"); |
| 27 | |
| 28 | return 0; |
| 29 | } |
(Edited: In FD_SET(0, &rfds); he sets socket 0 (stdin) in the bag for sockets to listen. Then calls select with 1 as first parameter (highest descriptor in all bags, in this case 0, plus one). tv holds how long select will wait for connections. Here is set for five seconds, so the program will block for 5 seconds in select. If you set 0, it becomes non-blocking.)
ok and what to do that the receive function isn't blocking?
The only way I remember to make recv non blocking is using fcntl. With select, you peek the socket, if it has something, you call recv (which is still blocking, but since you know there is something to read, it returns immediately. If you need some code example from me, you need to wait until I go back home
1.
you mean if a have a server thats sends all the time i could call the blocking functions without any lag, right?
2.
i read something about threaded servers as an alternative mehtod to select ones
3.
examples would be nice
backlog is NOT the number of clients you may have connected! The backlog parameter refers to the number of clients that are waiting for you to call accept. If you call listen with backlog 16, and before you call accept 17 people try to connect, 16 people will make it through, and 1 will be refused. When you call accept once, there will be 15 people pending. If 2 people try to connect then before the next accept call, one will be refused. So on and so forth. It is the number of pending connections waiting to be accepted before they are completely rejected.
1. Yep. You peek the connection. If there is a new connection, you accept it, if you have data to be received, you receive it.
2. Basically, Apache gets a connection, creates a child (I used fork, but guess it uses threads) and lets the child take care of that connection.
3. Ok, will find my old mutiple chat program
hmm so if i want to accept 32 clients then i have to set the backlog at least to 32 but better very high for there is the chance for as much as possible clients to wait (in a qeue) for my acception?
hmm so if i want to accept 32 clients then i have to set the backlog at least to 32 but better very high for there is the chance for as much as possible clients to wait (in a qeue) for my acception?
No. backlog is the amount of connections you can have pending - read gillius' explanation again.
Here's a simple example: think of it as a queue outside a club - the queue size determines the number of people (connections) who can wait outside (pending connections) to be let inside (accept()ed) by the bouncers . If the club seats 32 people they can still have a queue with room for only one, as long as the guests arrive one at a time before being let in. However, if two people arrive at the same time (or between checks by the bouncer if there's someone to be let in), the first one will be put in the queue while the other is simply refused entry and is lost to the club as a customer. With a queue size of two, two people can wait outside, etc.
Hope that was simple enough
| 1 | #ifdef WIN32 |
| 2 | #include <Winsock2.h> |
| 3 | #else |
| 4 | #include <sys/types.h> |
| 5 | #include <sys/socket.h> |
| 6 | |
| 7 | #define closesocket close |
| 8 | #endif |
| 9 | #include <stdio.h> |
| 10 | |
| 11 | #define D_PORT 4344 |
| 12 | #define D_HOST "localhost" |
| 13 | #define D_QUEUE 32 |
| 14 | #define D_SOCKETS 16 |
| 15 | #define D_INFO 256 |
| 16 | |
| 17 | int main(int argc, char **argv) { |
| 18 | struct timeval tv; |
| 19 | struct sockaddr_in addr; |
| 20 | struct hostent *host; |
| 21 | unsigned int descriptor; |
| 22 | int result; |
| 23 | int index; |
| 24 | int cycle = 0; |
| 25 | int delay = 0; |
| 26 | unsigned int sockets[D_SOCKETS]; |
| 27 | int sockets_index = 0; |
| 28 | unsigned int maximun; |
| 29 | char buffer[D_INFO]; |
| 30 | fd_set input; |
| 31 | |
| 32 | /* read the delay if any */ |
| 33 | if (argc > 1) |
| 34 | delay = atol(argv[1]); |
| 35 | else |
| 36 | delay = 0; |
| 37 | |
| 38 | #ifdef WIN32 |
| 39 | WSADATA wsaData; |
| 40 | WSAStartup(MAKEWORD(2, 2), &wsaData); |
| 41 | #endif /* WIN32 */ |
| 42 | |
| 43 | /* create a socket */ |
| 44 | descriptor = socket(PF_INET, SOCK_STREAM, 0); |
| 45 | if (descriptor == -1) { |
| 46 | perror("socket"); |
| 47 | return (1); |
| 48 | } |
| 49 | |
| 50 | /* get information about the host */ |
| 51 | memset(&addr, 0, sizeof(addr)); |
| 52 | host = gethostbyname(D_HOST); |
| 53 | if (host == NULL) { |
| 54 | perror("gethostbyname"); |
| 55 | closesocket(descriptor); |
| 56 | #ifdef WIN32 |
| 57 | WSACleanup(); |
| 58 | #endif |
| 59 | return (1); |
| 60 | } |
| 61 | |
| 62 | /* bind the socket to an address and port */ |
| 63 | memcpy(&addr.sin_addr, host->h_addr_list[0], sizeof(host->h_addr_list[0])); |
| 64 | addr.sin_family = AF_INET; |
| 65 | addr.sin_port = htons(D_PORT); |
| 66 | result = bind(descriptor, (struct sockaddr *)&addr, sizeof(addr)); |
| 67 | if (result == -1) { |
| 68 | perror("bind"); |
| 69 | closesocket(descriptor); |
| 70 | #ifdef WIN32 |
| 71 | WSACleanup(); |
| 72 | #endif |
| 73 | return (1); |
| 74 | } |
| 75 | |
| 76 | /* listen for connections */ |
| 77 | result = listen(descriptor, D_QUEUE); |
| 78 | if (result == -1) { |
| 79 | perror("listen"); |
| 80 | closesocket(descriptor); |
| 81 | #ifdef WIN32 |
| 82 | WSACleanup(); |
| 83 | #endif |
| 84 | return (1); |
| 85 | } |
| 86 | |
| 87 | memset(sockets, 0, sizeof(sockets)); |
| 88 | maximun = descriptor; |
| 89 | |
| 90 | result = 0; |
| 91 | while (result != -1) { |
| 92 | FD_ZERO(&input); |
| 93 | FD_SET(descriptor, &input); |
| 94 | for (result = 0; result < sockets_index; result++) |
| 95 | FD_SET(sockets[result], &input); |
| 96 | |
| 97 | tv.tv_sec = delay; |
| 98 | tv.tv_usec = 0; |
| 99 | if (delay == -1) |
| 100 | result = select(maximun + 1, &input, NULL, NULL, NULL); |
| 101 | else |
| 102 | result = select(maximun + 1, &input, NULL, NULL, &tv); |
| 103 | switch (result) { |
| 104 | /* error in select */ |
| 105 | case -1: |
| 106 | perror("select"); |
| 107 | break; |
| 108 | |
| 109 | /* nothing to process */ |
| 110 | case 0: |
| 111 | break; |
| 112 | |
| 113 | /* a number of sockets are ready for reading */ |
| 114 | default: |
| 115 | /* check if the descriptor set is our listening one */ |
| 116 | if (FD_ISSET(descriptor , &input)) { |
| 117 | sockets[sockets_index] = accept(descriptor, NULL, NULL); |
| 118 | if (sockets[sockets_index] == -1) { |
| 119 | perror("accept"); |
| 120 | } |
| 121 | else { |
| 122 | if (sockets[sockets_index] > maximun) |
| 123 | maximun = sockets[sockets_index]; |
| 124 | |
| 125 | sockets_index++; |
| 126 | } |
| 127 | } |
| 128 | /* one of the sockets is sending data. Find it */ |
| 129 | else { |
| 130 | for (index = 0; index < sockets_index; index++) { |
| 131 | if (FD_ISSET(sockets[index], &input)) { |
| 132 | memset(buffer, 0, sizeof(buffer)); |
| 133 | |
| 134 | /* read information from socket */ |
| 135 | result = recv(sockets[index], buffer, sizeof(buffer), 0); |
| 136 | if (result == -1) |
| 137 | perror("recv"); |
| 138 | else |
| 139 | printf("Received %d bytes from descriptor %d: %s\n", result, sockets[index], buffer); |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | printf("%d\r", cycle++); |
| 146 | } |
| 147 | |
| 148 | for (result = 0; result < sockets_index; result++) { |
| 149 | closesocket(sockets[sockets_index]); |
| 150 | } |
| 151 | |
| 152 | closesocket(descriptor); |
| 153 | #ifdef WIN32 |
| 154 | WSACleanup(); |
| 155 | #endif |
| 156 | |
| 157 | return (0); |
| 158 | } |
Ok, here is a very small program. Put this into a file and add it to a VC project, add Ws2_32.lib library for linking, and compile it. Under MinGW, use g++ main.cpp -o main.exe -lwsock32. Execute it. By default, it is a non blocking program. There is a number counting advancing to show you it is not blocking the execution.
Now, run a telnet (telnet localhost 4344). Telnet will connect, and everytime you type something, it will send the letter to the server. You can connect up to 32 telnets. Every time you type a letter, the server prints the socket and the letter. If you see the Task Manager, the program would be taking like 99% of CPU.
If you want your server to wait for 1 second before continuing processing, pass 1 as argument. You will notice I set the new delay. This time, the server will wait for 1 second before continuing with the program. Finally, if you want to make the program blocking, pass -1 as argument. If you check the code, I call select with NULL as last parameter to block it.
Be careful! I am not doing error handling when a telnet shuts down, so if you do it will get mad
I hope the example is good enough.
(Edited: Non-Windows support is not tested, too sleepy to turn my other computer on, but should work with one or two hacks).
Two notes:
- Windows limits waiting connections queue to 5 (probably Linux does it too) so passing anything greater than 5 to listen() will behave as you've passed 5.
- There is no fcntl under Windows, but there is ioctlsocket() which can be used to set blocking mode and is similar to Linux ioctl().
If you'd like to look at wrapper I've written and C++ with STL doesn't scare you, click links below. 
http://sphere.pl/~krzysiek/files/netwrapper.cpp
http://sphere.pl/~krzysiek/files/netwrapper.h
Linux support isn't implemented yet, but it won't be hard.
Compatibility
The backlog parameter is limited (silently) to a reasonable value as determined by the underlying service provider. Illegal values are replaced by the nearest legal value. There is no standard provision to find out the actual backlog value.
Could it be that TCP/IP limits it to 5, and so anytime using *_INET family it is limited to 5?
i think i got it now
nice explanation gnolam.
so for me it is good to take the maximum 5...
i'll try your pieces of code now...
btw what version of winsock is "the best" to use?
1.1 is a bit out of date, and there are 2.0 and i believe 2.2...
2.0 sounds good to me
If you don't need features present only in 2.0 you don't really have a reason to use it...
so you think better using 1.1 for better compatibility?
Yes. It's likely that everything you need is in 1.1, and that will also ensure portability as you will mostly be using BSD socket functions, which are easily ported to any *nix platform later.
Hmm... it is most likely even Win95 uses 2.0 (I always had to download the Windows Update to fix some IE problems). But if you are just sending information, 1.0 or 1.1 should work. I am not sure which bugs 2.0 fixed, though. My choose is to go to 2.0, and if someone is using Win95, they should install the Winsock update (like 700kb).
that's right the winsock 2 update isn't so hard to do.
(hmmm anyone knows how to give credits here in this forum)