Sockets - Threads
Sockets - Threads
Programming and
Socket
Outlin
e
1 Socket model
A complete
example
2 Concurrent
servers
Client Server
model
In client-server model:
The server is initially blocked waiting for
connection requests by the clients;
communication is initiated by the client;
the client needs to know the address of the
server, while the server accepts connections by
any client;
Once the communication channel has been
established, the server knows the client address,
and communication can be carried on from both
sides (initiated by the server or by the client).
Socket
s
#include <sys/socket.h>
Input arguments:
family Specifies the protocol family.
type It specifies the kind of connection that will be established on the
socket protocol Protocol that will be used. Usually set equal to 0 (the
default protocol), as the
pair (family, type) usually identifies a default protocol.
We will only
analyze the combination
family=AF_INET and type=SOCK_STREAM, that
correspondes to TCP/IP. However, there are other
possibilities:
family Description
AF_INET IPv4 protocols type Description
AF_INET6 IPv6 protocols SOCK_STREAM stream socket
AF_LOCAL Unix domain protocols SOCK_DGRAM datagram socket
AF_ROUTE Routing sockets SOCK_RAW raw socket
AF_KEY Key sockets
Table: Socket
Table: Protocol type
families
TCP/IP connection
scheme TCP Server
socket()
bind()
listen()
TCP Client
socket()
accept()
three−way handshake
connect() Blocked, waiting for
connections from clients
write() read()
read() write()
Figure: Connection
scheme
Server
sequence
This is the list of calls in the
server: socket creation
bind
listen
accep
t
Server
sequence
This is the list of calls in the
server: socket creation
bind
listen
accep
t
Let’s start
from the
bind
It binds
the
socke
t to a
specif
ic
Internet
addresses
struct in_addr {
in_addr_t s_addr; /* IPv4 address (32 bit) */
};
Getting IP
address
Usually the IP address is unique for each node
Should not be encoded in the program
(otherwise the
program cannot be ported on another computer
without re-compiling)
It is possible to implicitely let the OS set the IP
address of the socket by setting the s_addr field of
the struct in_addr to
INADDR_ANY
Getting IP
address
Usually the IP address is unique for each node
Should not be encoded in the program
(otherwise the
program cannot be ported on another computer
without re-compiling)
It is possible to implicitely let the OS set the IP
address of the socket by setting the s_addr field of
the struct in_addr to
INADDR_ANY
Example:
struct sockaddr_in my_addr;
int myport = 50000;
accep
t
Liste
n
#include <sys/socket.h>
Input arguments:
sockfd socket descriptor (returned by socket()
backlog maximum number of connection requests that can be buffered
before being processed by the accept().
accep
t
Accep
t
#include <sys/socket.h>
Input arguments:
sockfd passive socket deswcriptor on which the server will block waiting
for incoming connection requests
cliaddr if the function returns succesfully, contains the internet address (IP +
port) of the client that has sent the request
addrlen when the function returns, it contains the lenght in bytes of the
structure cliaddr
Return value:
The function will return a new socket descriptor that will be used
for communication with the client
In case or error, returns -1
Input arguments:
sockfd the socket descriptor that will be used for communication (active)
saddr pointer to a structure that contains the Internet address (IP + port) of
the server addrlen lenght in bytes of the structure given as second paramter
Return value:
0 if the connection was correctly established
-1 in case of error
s1 = gethostbyname("www.sssup.it");
s2 = gethostbyname("www.ing.unipi.it");
Example: the
client
A simple example: a server that transforms all
characters of a string into capital letters.
struct sockaddr_in s_addr;
struct hostent *server;
s_port = atoi(argv[2]);
bcopy((char*)server->h_addr,
(char*)&s_addr.sin_addr.s_addr,
server->h_length);
if (listen(sd, 5) < 0)
sys_err("listen failed!");
printf("Server listening on
port %d\n", myport);
return sd;
}
Example: the
server
Now the main cycle: notice that we move the actual
service into a separate service routine do_service().
int main(int argc, char *argv[])
{
struct sockaddr_in c_add;
int base_sd, curr_sd;
int addrlen;
int myport;
int err =
0;
base_sd = init_sd(myport);
while (!err) {
curr_sd = accept(base_sd, CAST_ADDR(&c_add),
&addrlen);
if (curr_sd < 0) sys_err("accept failed!");
do_service(curr_sd);
close(curr_sd);
}
Example: the service
routine
do {
l = read(sd, msg, BUFFERSIZE - 1);
if (l == 0) break;
msg[l] = 0;
printf("Server:
received %s\n",
msg);
for (i=0; i<l; i++) msg[i] = toupper(msg[i]);
printf("Server: sending %s\n", msg);
write(sd, msg, l);
} while (l!=0);
}
Outlin
e
1 Socket model
A complete
example
2 Concurrent
servers
Why concurrency in
servers
In previous examples, we have shown a sequential
server. It serves requests sequentially, in order
of arrival (FIFO)
A client has to wait for all preceding requests and
for its request to be served before getting the
response Problems:
A short request by a client may have to wait for
longer requests to be completed
The server can be blocked on I/O while serving a
request; this is inefficient!
A solution is to have concurrent servers:
Multi-process: one process per client (dynamically
created, or “pre-forked”);
Multi-thread: one thread per client (dynamically
created, or pre-created).
Multi-process
servers
int main(int argc, char *argv[])
{
struct sockaddr_in c_add;
int base_sd, curr_sd;
int addrlen;
int myport;
int err = 0;
int ch=0;
base_sd = init_sd(myport);
signal(SIGCHLD, sig_child);
while (!err) {
if ( (curr_sd =
accept(base_sd,
CAST_ADDR(&c_add),
&addrlen)) < 0) {
if (errno == EINTR)
continue;
else sys_err("accept
failed!");
}
ch = fork();
if (ch == 0)
{ do_service(curr_s
d); close(curr_sd);
exit(0);
}
close (curr_sd);
}
close(base_sd);
Multi-process servers
- II
pthread_detach(pthread_self());
do_service(sd);
close(sd);
}
base_sd = init_sd(myport);
while (!err) {
curr_sd = accept(base_sd, CAST_ADDR(&c_add), &addrlen);
if (curr_sd < 0) sys_err("accept failed!");
pthread_create(&tid, 0, body, (void *)curr_sd);
}
}
Multi-thread
server
To avoid zombie threads, we use pthread_detach to
detach the thread, so that the main does not
need to wait with
pthead_join
Multi-thread
server
To avoid zombie threads, we use pthread_detach to
detach the thread, so that the main does not
need to wait with
pthead_join
while (1)
{ pthread_mutex_lock(&m_ac
c);
sd = accept(base_sd,
CAST_ADDR(&c_add),
&addrlen);
pthread_mutex_unlock(&m_acc);
do_service(sd);
close(sd);
Pre-created
threads
int main(int argc, char *argv[])
{
int i;
int base_sd;
int myport;
base_sd = init_sd(myport);
pthread_mutex_init(&m_acc, 0);
pause();
}