Libasync tutorial

Lesson 6: Server sockets

Prev Index Next

Function inetsocket creates a socket but, unlike tcpconnect, does not connect it. Here's the prototype:

int inetsocket(int type, int_16 port);
or
int inetsocket(int type, int_16 port, u_int32_t addr);

inetsocket does bind the socket to the specified port and address. type should be SOCK_STREAM for a TCP socket and SOCK_DGRAM for a UDP socket. (The optional addr parameter is to make the socket available on a specific local interface only.) Note that inetsocket does not put the socket in non-blocking mode. You have to call libasync's make_async to make it non-blocking.

What follows is an example of an echo-server, i.e., a server that writes back to the client whatever it reads from the client. Notice that most of the code is remarkably similar to the HTTP client from the previous lesson.

examples/inetsocket.C

 1:   #include "async.h"
 2:   
 3:   void
 4:   echo_write(int fd, strbuf buf)
 5:   {
 6:     int n = buf.tosuio()->output(fd);
 7:   
 8:     if(n < 0)
 9:       fatal << "write\n";
10:   
11:     // still stuff to write: don't disable writability callback
12:     if(buf.tosuio()->resid())
13:       return;
14:   
15:     fdcb(fd, selwrite, 0);
16:   }
17:   
18:   
19:   
20:   void
21:   echo_read(int fd)
22:   {
23:     strbuf buf;
24:     int n = buf.tosuio()->input(fd);
25:   
26:     if(n < 0)
27:       fatal << "read\n";
28:   
29:     if(n == 0) {
30:       fdcb(fd, selread, 0);
31:       close(fd);
32:       return;
33:     };
34:   
35:     fdcb(fd, selwrite, wrap(echo_write, fd, buf));
36:   }
37:   
38:   void
39:   accept_connection(int fd)
40:   {
41:     struct sockaddr_in sin;
42:     unsigned sinlen = sizeof(sin);
43:   
44:     int cs = accept(fd, (struct sockaddr *) &sin, &sinlen);
45:     if (cs >= 0) {
46:       warn << "accepted connection. file descriptor = " << cs << "\n";
47:     } else if (errno != EAGAIN)
48:       fatal << "accept; errno = " << errno << "\n";
49:   
50:     fdcb(cs, selread, wrap(echo_read, cs));
51:   }
52:     
53:   
54:   int
55:   main(int argc, char *argv[]) 
56:   {
57:     if(argc < 2)
58:       fatal << "usage: inetsocket port\n";
59:   
60:     int fd = inetsocket(SOCK_STREAM, atoi(argv[1]));
61:     if (fd < 0)
62:       fatal << "inetsocket\n";
63:     make_async(fd);
64:     if (listen(fd, 5) < 0)
65:       fatal << "listen\n";
66:   
67:     fdcb(fd, selread, wrap(accept_connection, fd));
68:   
69:     amain();
70:   }

Line 24 creates a new socket bound to port 2206. The call to make_async on line 27 puts the socket in non-blocking mode. listen causes the socket to wait for incoming connections. The call to fdcb on line 31 tells libasync to call accept_connection when someone tries to connect to the server we just spun off.

accept_connection accepts client connections by calling accept, prints out a message, and then terminates the program properly.

more explanation comes here...

Prev Index Next

Back to main.