Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » winsocks listen()

This thread is locked; no one can reply to it. rss feed Print
 1   2 
winsocks listen()
Frank Drebin
Member #2,987
December 2002
avatar

what is the backlog in the int listen (SOCKET s, int backlog); function good for ???

gnolam
Member #2,030
March 2002
avatar

Quoted directly from MSDN:

Quote:

<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...

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

ReyBrujo
Moderator
January 2001
avatar

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.

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Frank Drebin
Member #2,987
December 2002
avatar

so if i want a server where 32 clients can connect at max i'll use 32 ?

ReyBrujo
Moderator
January 2001
avatar

Yep

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Frank Drebin
Member #2,987
December 2002
avatar

and it just set the socket in the listen mode or does it wait until 32 clients have connected?

ReyBrujo
Moderator
January 2001
avatar

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

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Frank Drebin
Member #2,987
December 2002
avatar

[edited]
and accept is a blocking function... how can i stop it

ReyBrujo
Moderator
January 2001
avatar

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.

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Frank Drebin
Member #2,987
December 2002
avatar

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?

ReyBrujo
Moderator
January 2001
avatar

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 
6int
7main(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.)

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Frank Drebin
Member #2,987
December 2002
avatar

ok and what to do that the receive function isn't blocking?

ReyBrujo
Moderator
January 2001
avatar

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 :)

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Frank Drebin
Member #2,987
December 2002
avatar

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 :D

gillius
Member #119
April 2000

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.

Gillius
Gillius's Programming -- https://gillius.org/

ReyBrujo
Moderator
January 2001
avatar

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 :)

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Frank Drebin
Member #2,987
December 2002
avatar

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?

gnolam
Member #2,030
March 2002
avatar

Quote:

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 :)

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

ReyBrujo
Moderator
January 2001
avatar

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 
17int 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).

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Krzysztof Kluczek
Member #4,191
January 2004
avatar

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. :)

ReyBrujo
Moderator
January 2001
avatar

MSDN said:

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?

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Frank Drebin
Member #2,987
December 2002
avatar

i think i got it now ;D 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

X-G
Member #856
December 2000
avatar

If you don't need features present only in 2.0 you don't really have a reason to use it...

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Frank Drebin
Member #2,987
December 2002
avatar

so you think better using 1.1 for better compatibility?

X-G
Member #856
December 2000
avatar

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.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

 1   2 


Go to: