Socket Programming
Prepared By: Bijay Mishra
User and System Programs
Kernel Support
Hardware
Socket
What are Sockets?
Communication abstractions Support the TCP/IP protocol stack Provide access to both reliable (TCP) and unreliable (UDP) transport services Programming tools to implement client-server applications
Two types of sockets
o
connection-oriented (TCP) Connectionless (UDP)
What is a socket?
Socket: An interface between an application process and transport layer. The application process can send/receive messages to/from another application process (local or remote)via a socket.
In Unix jargon, a socket is a file descriptor an integer associated with an open file. Types of Sockets: Internet Sockets, unix sockets, X.25 sockets etc.
Types of Internet Sockets
Stream Sockets (SOCK_STREAM) Connection oriented Rely on TCP to provide reliable two-way connected communication Datagram Sockets (SOCK_DGRAM) Rely on UDP Connection is unreliable
Server and Client
Server and Client exchange messages over the network through a common Socket API
Clients
Server ports
user space
TCP/UDP IP Ethernet Adapter
Socket API
TCP/UDP IP Ethernet Adapter
kernel space
hardware
Socket programming with TCP
Client must contact server server process must first be running server must have created socket (door) that welcomes clients contact Client contacts server by: creating client-local TCP socket specifying IP address, port number of server process When client creates socket: client TCP establishes connection to server TCP When contacted by client, server TCP creates new socket for server process to communicate with client allows server to talk with multiple clients
application viewpoint TCP provides reliable, in-order transfer of bytes (pipe) between client and server
Server socket()
Socket for Connection-oriented EXAMPLE (TCP)
bind()
listen() accept()
blocks until connection from client
Connection establishment
Client
socket()
connect() write() read()
read()
Process request
Data (request)
write()
Data (reply)
TCP Server
Web Server
For example: web server
What does a web server need to do so that a web client can connect to it?
Port 80
TCP
IP
Ethernet Adapter
socket() call
int fd; /* socket descriptor */ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) } perror(socket); exit(1); }
family : address family (protocol family)
AF_UNIX, AF_INET, AF_NS, AF_IMPLINK socket returns an integer (socket descriptor) fd < 0 indicates that an error occurred socket descriptors are similar to file descriptors AF_INET: associates a socket with the Internet protocol family SOCK_STREAM: selects the TCP protocol SOCK_DGRAM: selects the UDP protocol
bind() call
A socket can be bound to a port
int fd; struct sockaddr_in srv; /* create the socket */ /* socket descriptor */ /* used by bind() */
srv.sin_family = AF_INET; /* use the Internet addr family */
srv.sin_port = htons(80); /* bind socket fd to port 80*/ /* bind: a client may connect to any of my addresses */ srv.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(fd, (struct sockaddr*) &srv, sizeof(srv)) < 0) { perror("bind"); exit(1); }
Still not quite ready to communicate with a client...
listen() call
listen indicates that the server will accept a connection
int fd; struct sockaddr_in srv; /* socket descriptor */ /* used by bind() */
/* 1) create the socket */ /* 2) bind the socket to a port */ if(listen(fd, 5) < 0) { perror(listen); exit(1); }
Still not quite ready to communicate with a client...
accept() call
accept blocks waiting for a connection
int fd; /* socket descriptor */ struct sockaddr_in srv; /* used by bind() */ struct sockaddr_in cli; /* used by accept() */ int newfd; /* returned by accept() */ int cli_len = sizeof(cli); /* used by accept() */ /* 1) create the socket */ /* 2) bind the socket to a port */ /* 3) listen on the socket */ newfd = accept(fd, (struct sockaddr*) &cli, &cli_len); if(newfd < 0) { perror("accept"); exit(1); }
accept returns a new socket (newfd) with the same properties as the original socket (fd) newfd < 0 indicates that an error occurred
accept() call
struct sockaddr_in cli; int newfd; int cli_len = sizeof(cli); /* used by accept() */ /* returned by accept() */ /* used by accept() */
newfd = accept(fd, (struct sockaddr*) &cli, &cli_len); if(newfd < 0) { perror("accept"); exit(1); }
How does the server know which client it is?
cli.sin_addr.s_addr contains the clients IP address cli.sin_port contains the clients port number
Now the server can exchange data with the client by using read and write on the descriptor newfd. Why does accept need to return a new descriptor?
read() call
read can be used with a socket read blocks waiting for data from the client but does not guarantee that sizeof(buf) is read
int fd; char buf[512]; int nbytes; /* /* /* /* 1) 2) 3) 4) /* socket descriptor */ /* used by read() */ /* used by read() */
create the socket */ bind the socket to a port */ listen on the socket */ accept the incoming connection */
if((nbytes = read(newfd, buf, sizeof(buf))) < 0) { perror(read); exit(1); }
TCP Client
For example: web client
2 Web Clients
How does a web client connect to a web server?
TCP
IP
Ethernet Adapter
Dealing with IP Addresses
IP Addresses are commonly written as strings (128.2.35.50), but programs deal with IP addresses as integers. Converting strings to numerical address:
struct sockaddr_in srv; srv.sin_addr.s_addr = inet_addr(128.2.35.50); if(srv.sin_addr.s_addr == (in_addr_t) -1) { fprintf(stderr, "inet_addr failed!\n"); exit(1); }
Converting a numerical address to a string:
struct sockaddr_in srv; char *t = inet_ntoa(srv.sin_addr); if(t == 0) { fprintf(stderr, inet_ntoa failed!\n); exit(1); }
Translating Names to Addresses
Gethostbyname provides interface to DNS Additional useful calls
Gethostbyaddr returns hostent given sockaddr_in Getservbyname
Used to get service description (typically port number) Returns servent based on name
#include <netdb.h> struct hostent *hp; /*ptr to host info for remote*/ struct sockaddr_in peeraddr; char *name = www.gunadarma.ac.id; peeraddr.sin_family = AF_INET; hp = gethostbyname(name) peeraddr.sin_addr.s_addr = ((struct in_addr*)(hp->h_addr))->s_addr;
connect() call
connect allows a client to connect to a server...
int fd; struct sockaddr_in srv; /* create the socket */ /* connect: use the Internet address family */ srv.sin_family = AF_INET; /* connect: socket fd to port 80 */ srv.sin_port = htons(80); /* connect: connect to IP Address 128.2.35.50 */ srv.sin_addr.s_addr = inet_addr(128.2.35.50); if(connect(fd, (struct sockaddr*) &srv, sizeof(srv)) < 0) { perror(connect"); exit(1); } /* socket descriptor */ /* used by connect() */
write() call
write can be used with a socket
int fd; struct sockaddr_in srv; char buf[512]; int nbytes; /* /* /* /* socket descriptor */ used by connect() */ used by write() */ used by write() */
/* 1) create the socket */ /* 2) connect() to the server */ /* Example: A client could write a request to a server */ if((nbytes = write(fd, buf, sizeof(buf))) < 0) { perror(write); exit(1); }
Socket programming with UDP
UDP: no connection between client and server no handshaking sender explicitly attaches IP address and port of destination server must extract IP address, port of sender from received datagram UDP: transmitted data may be received out of order, or lost
application viewpoint UDP provides unreliable transfer of groups of bytes (datagrams) between client and server
Socket for Connectionless (UDP)
Server socket() bind() recvfrom()
blocks until connection from client
Data (request)
Client
socket() bind() sendto()
Process request
write()
Data (reply)
recvfrom()
UDP Server Example
NTP daemon Port 123 UDP
For example: NTP daemon
What does a UDP server need to do so that a UDP client can connect to it?
IP
Ethernet Adapter
socket() call
The UDP server must create a datagram socket
int fd; /* socket descriptor */
if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror(socket); exit(1); }
socket returns an integer (socket descriptor) fd < 0 indicates that an error occurred AF_INET: associates a socket with the Internet protocol family SOCK_DGRAM: selects the UDP protocol
bind() call
A socket can be bound to a port
int fd; struct sockaddr_in srv; /* create the socket */ /* bind: use the Internet address family */ srv.sin_family = AF_INET; /* socket descriptor */ /* used by bind() */
/* bind: socket fd to port 80*/ srv.sin_port = htons(80);
/* bind: a client may connect to any of my addresses */ srv.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(fd, (struct sockaddr*) &srv, sizeof(srv)) < 0) { perror("bind"); exit(1); }
Now the UDP server is ready to accept packets
recvfrom() call
read does not provide the clients address to the UDP server
int fd; struct sockaddr_in srv; struct sockaddr_in cli; char buf[512]; int cli_len = sizeof(cli); int nbytes; /* 1) create the socket */ /* 2) bind to the socket */ nbytes = recvfrom(fd, buf, sizeof(buf), 0 /* flags */, (struct sockaddr*) &cli, &cli_len); if(nbytes < 0) { perror(recvfrom); exit(1); } /* /* /* /* /* /* socket descriptor */ used by bind() */ used by recvfrom() */ used by recvfrom() */ used by recvfrom() */ used by recvfrom() */
recvfrom() call
nbytes = recvfrom(fd, buf, sizeof(buf), 0 /* flags */, (struct sockaddr*) cli, &cli_len);
The actions performed by recvfrom
returns the number of bytes read (nbytes) copies nbytes of data into buf returns the address of the client (cli) returns the length of cli (cli_len) dont worry about flags
UDP Client Example
2 UDP Clients
How does a UDP client communicate with a UDP server? ports
TCP
IP
Ethernet Adapter
sendto() call
write is not allowed Notice that the UDP client does not bind a port number a port number is dynamically assigned when the first sendto is called
int fd; struct sockaddr_in srv; /* 1) create the socket */ /* sendto: send data to IP Address 128.2.35.50 port 80 */ srv.sin_family = AF_INET; srv.sin_port = htons(80); srv.sin_addr.s_addr = inet_addr(128.2.35.50); nbytes = sendto(fd, buf, sizeof(buf), 0 /* flags */, (struct sockaddr*) &srv, sizeof(srv)); if(nbytes < 0) { perror(sendto); exit(1); } /* socket descriptor */ /* used by sendto() */
The UDP Server
UDP Server Port 3000 Port 2000
How can the UDP server service multiple ports simultaneously?
UDP
IP
Ethernet Adapter
UDP Server: Servicing Two Ports
int s1; int s2; /* /* /* /* 1) 2) 3) 4) create socket s1 */ create socket s2 */ bind s1 to port 2000 */ bind s2 to port 3000 */ /* socket descriptor 1 */ /* socket descriptor 2 */
while(1) { recvfrom(s1, buf, sizeof(buf), ...); /* process buf */ recvfrom(s2, buf, sizeof(buf), ...); /* process buf */ }
What problems does this code have?
select()call
int select(int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
FD_CLR(int fd, fd_set *fds); FD_ISSET(int fd, fd_set *fds); FD_SET(int fd, fd_set *fds); FD_ZERO(fd_set *fds); /* /* /* /* clear the bit for fd in fds */ is the bit for fd in fds? */ turn on the bit for fd in fds */ clear all bits in fds */
maxfds: number of descriptors to be tested
descriptors (0, 1, ... maxfds-1) will be tested
readfds: a set of fds we want to check if data is available
returns a set of fds ready to read if input argument is NULL, not interested in that condition
writefds: returns a set of fds ready to write exceptfds: returns a set of fds with exception conditions
select() call
int select(int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); struct timeval { long tv_sec; long tv_usec; }
/* seconds / /* microseconds */
timeout
if NULL, wait forever and return only when one of the descriptors is ready for I/O otherwise, wait up to a fixed amount of time specified by timeout
if we dont want to wait at all, create a timeout structure with timer value equal to 0
Refer to the man page for more information
select() call
select allows synchronous I/O multiplexing
int s1, s2; fd_set readfds; /* socket descriptors */ /* used by select() */ /* create and bind s1 and s2 */ while(1) { FD_ZERO(&readfds); /* initialize the fd set */ FD_SET(s1, &readfds); /* add s1 to the fd set */ FD_SET(s2, &readfds); /* add s2 to the fd set */ if(select(s2+1, &readfds, 0, 0, 0) < 0) { perror(select); exit(1); } if(FD_ISSET(s1, &readfds)) { recvfrom(s1, buf, sizeof(buf), ...); /* process buf */ } /* do the same for s2 */ }
Bijay Mishra
9841695609 biizay.blogspot.com [email protected]