22-Sep-17
Server and Client
Server and Client exchange messages over the
network through a common Socket API
Clients
Server user
ports space
Socket programming in C
TCP/UDP TCP/UDP
Socket API kernel
space
IP IP
Ethernet Adapter Ethernet Adapter hardware
Concept of Port Numbers Names and Addresses
–Port numbers are used to identify
“entities” on a host (16 bit) NTP Web • Each attachment point on Internet is given
–Port numbers can be daemon server unique address
• Well-known (port 0-1023)
port 123
• Registered (port 1024 – 49151) port 80 – Based on location within network – like phone
• Dynamic or private (port 49152-65535) numbers
–Servers/daemons usually use well- TCP/UDP
known ports • Humans prefer to deal with names not addresses
• Any client can identify the server/service IP – DNS provides mapping of name to address
• HTTP = 80, FTP = 21, Telnet = 23, ...
• /etc/services defines well-known ports – Name based on administrative ownership of host
Ethernet Adapter
–Clients usually use dynamic ports
• Assigned by the kernel at run time
1
22-Sep-17
Internet Addressing Data
Byte Ordering
Structure
#include <netinet/in.h> union {
u_int32_t addr; /* unsigned long int, 4
/* Internet address structure */ bytes address */
struct in_addr { unsigned char c[4];
u_long s_addr; /* 32-bit IPv4 address */ } un;
}; /* network byte ordered */ /* 128.2.194.95 */
un.addr = 0x8002c25f;
/* Socket address, Internet style. */ /* un.c[0] = ? */ c[0] c[1] c[2] c[3]
struct sockaddr_in {
u_char sin_family; /* Address Family */
u_short sin_port; /* UDP or TCP Port# */
• Big Endian 128 2 194 95
/* network byte ordered */ – Sun Solaris, PowerPC, ...
struct in_addr sin_addr; /* Internet Address */ 95 194 2 128
• Little Endian
char sin_zero[8]; /* unused */
}; – i386, alpha, ...
• Network byte order = Big Endian
• sin_family = AF_INET selects Internet address family
• Byte Order
– Different computers may have different internal representation of 16 / 32-
bit integer (called host byte order).
Byte Ordering Functions
– Examples • Converts between host byte order and network byte
• Big-Endian byte order (e.g., used by Motorola 68000): order
– ‘h’ = host byte order
– ‘n’ = network byte order
– ‘l’ = long (4 bytes), converts IP addresses
– ‘s’ = short (2 bytes), converts port numbers
• Little-Endian byte order (e.g., used by Intel 80x86): #include <netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsigned short int netshort);
2
22-Sep-17
What is a Socket? TCP Server
• A socket is a file descriptor that lets an application read/write data from/to the
network • For example: web server
int fd; /* socket descriptor */ Web Server
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) }
perror(“socket”); Port 80 • What does a web server
exit(1); need to do so that a web
} client can connect to it?
TCP
• socket returns an integer (socket descriptor)
– fd < 0 indicates that an error occurred
IP
– socket descriptors are similar to file descriptors
• AF_INET: associates a socket with the Internet protocol family Ethernet Adapter
• SOCK_STREAM: selects the TCP protocol
• SOCK_DGRAM: selects the UDP protocol
Socket I/O: socket() Socket I/O: bind()
• Since web traffic uses TCP, the web server must create a socket of type
SOCK_STREAM • A socket can be bound to a port
int fd; /* socket descriptor */
int fd; /* socket descriptor */ struct sockaddr_in srv; /* used by bind() */
/* create the socket */
if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror(“socket”); srv.sin_family = AF_INET; /* use the Internet addr family */
exit(1);
srv.sin_port = htons(80); /* bind socket ‘fd’ to port 80*/
}
/* bind: a client may connect to any of server addresses */
• socket returns an integer (socket descriptor) srv.sin_addr.s_addr = htonl(INADDR_ANY);
– fd < 0 indicates that an error occurred
if(bind(fd, (struct sockaddr*) &srv, sizeof(srv)) < 0) {
• AF_INET associates a socket with the Internet protocol family perror("bind"); exit(1);
• SOCK_STREAM selects the TCP protocol }
• Still not quite ready to communicate with a client...
3
22-Sep-17
Socket I/O: listen() Socket I/O: accept()
• listen indicates that the server will accept a connection • accept blocks waiting for a connection
int fd; /* socket descriptor */
int fd; /* socket descriptor */ struct sockaddr_in srv; /* used by bind() */
struct sockaddr_in srv; /* used by bind() */ struct sockaddr_in cli; /* client’s add used by accept() */
int newfd; /* returned by accept() */
/* 1) create the socket */ int cli_len = sizeof(cli); /* used by accept() */
/* 2) bind the socket to a port */
/* 1) create the socket */
/* 2) bind the socket to a port */
if(listen(fd, 5) < 0) {
/* 3) listen on the socket */
perror(“listen”);
exit(1); newfd = accept(fd, (struct sockaddr*) &cli, &cli_len);
} if(newfd < 0) {
perror("accept"); exit(1);
}
• Still not quite ready to communicate with a client... • accept returns a new socket (newfd) with the same properties as the original
socket (fd)
– newfd < 0 indicates that an error occurred
Socket I/O: accept() continued... Socket I/O: read()
struct sockaddr_in cli; /* used by accept() */ • read can be used with a socket
int newfd; /* returned by accept() */
int cli_len = sizeof(cli); /* used by accept() */ • read blocks waiting for data from the client but does not
guarantee that sizeof(buf) is read
newfd = accept(fd, (struct sockaddr*) &cli, &cli_len);
if(newfd < 0) { int fd; /* socket descriptor */
perror("accept"); char buf[512]; /* used by read() */
int nbytes; /* used by read() */
exit(1);
}
/* 1) create the socket */
• How does the server know which client it is? /* 2) bind the socket to a port */
/* 3) listen on the socket */
– cli.sin_addr.s_addr contains the client’s IP address /* 4) accept the incoming connection */
/* 5) Create a child process to attend the connection */
– cli.sin_port contains the client’s port number /* Child will close fd, and continue communication with client */
/* parent will close newfd, and continue with accepting connection*/
• Now the server can exchange data with the client by using
read and write on the descriptor newfd. if((nbytes = read(newfd, buf, sizeof(buf))) < 0) {
perror(“read”); exit(1);
• Why does accept need to return a new descriptor? }
4
22-Sep-17
Dealing with IP Addresses
TCP Client
• IP Addresses are commonly written as strings (“128.2.35.50”), but programs
• For example: web client deal with IP addresses as integers.
2 Web Clients
Converting strings to numerical address:
• How does a web client struct sockaddr_in srv;
connect to a web server?
srv.sin_addr.s_addr = inet_addr(“128.2.35.50”);
if(srv.sin_addr.s_addr == (in_addr_t) -1) {
TCP fprintf(stderr, "inet_addr failed!\n"); exit(1);
}
Converting a numerical address to a string:
IP
struct sockaddr_in srv;
char *t = inet_ntoa(srv.sin_addr);
Ethernet Adapter if(t == 0) {
fprintf(stderr, “inet_ntoa failed!\n”); exit(1);
}
Translating Names to Addresses Socket I/O: connect()
• Gethostbyname provides interface to DNS • connect allows a client to connect to a server...
• Additional useful calls int fd; /* socket descriptor */
struct sockaddr_in srv; /* used by connect() */
– Gethostbyaddr – returns hostent given sockaddr_in
– Getservbyname /* create the socket */
• Used to get service description (typically port number) /* connect: use the Internet address family */
• Returns servent based on name srv.sin_family = AF_INET;
/* connect: socket ‘fd’ to port 80 */
#include <netdb.h> srv.sin_port = htons(80);
struct hostent *hp; /*ptr to host info for remote*/ /* connect: connect to IP Address “128.2.35.50” */
struct sockaddr_in peeraddr; srv.sin_addr.s_addr = inet_addr(“128.2.35.50”);
char *name = “www.tezu.ernet.in”;
if(connect(fd, (struct sockaddr*) &srv, sizeof(srv)) < 0) {
peeraddr.sin_family = AF_INET; perror(”connect"); exit(1);
hp = gethostbyname(name) }
peeraddr.sin_addr.s_addr = ((struct in_addr*)(hp->h_addr))->s_addr;
5
22-Sep-17
Socket I/O: write() Review: TCP Client-Server
• write can be used with a socket Interaction TCP Server
socket()
int fd; /* socket descriptor */
struct sockaddr_in srv; /* used by connect() */ bind()
char buf[512]; /* used by write() */
TCP Client listen()
int nbytes; /* used by write() */
socket() accept()
/* 1) create the socket */ connection establishment
/* 2) connect() to the server */ connect()
data request read()
/* Example: A client could “write” a request to a server write()
*/
if((nbytes = write(fd, buf, sizeof(buf))) < 0) { data reply write()
perror(“write”); read()
exit(1);
} end-of-file notification read()
close()
close()
from UNIX Network Programming by Stevens
Example: C client (TCP)
Socket programming with TCP
/* client.c */
Client must contact server void main(int argc, char *argv[])
• When contacted by client, {
• server process must first be
server TCP creates new struct sockaddr_in sad; /* structure to hold an IP address */
running int clientSocket; /* socket descriptor */
socket for server process to
• server must have created socket struct hostent *ptrh; /* pointer to a host table entry */
communicate with client
(door) that welcomes client’s char Sentence[128]; Create client socket,
– allows server to talk
contact char modifiedSentence[128]; connect to server
with multiple clients
Client contacts server by: – source port numbers host = argv[1]; port = atoi(argv[2]);
• creating client-local TCP socket used to distinguish clientSocket = socket(PF_INET, SOCK_STREAM, 0);
• specifying IP address, port clients. memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
application viewpoint sad.sin_family = AF_INET; /* set family to Internet */
number of server process sad.sin_port = htons((u_short)port);
• When client creates socket: TCP provides reliable, in-order ptrh = gethostbyname(host); /* Convert host name to IP address */
transfer of bytes (“pipe”) memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length); connect(clientSocket,
client TCP establishes between client and server (struct sockaddr *)&sad, sizeof(sad));
connection to server TCP
6
22-Sep-17
Example: C server (TCP)
Example: C client (TCP), cont.
/* server.c */
Get void main(int argc, char *argv[])
input stream gets(Sentence); {
from user struct sockaddr_in sad; /* structure to hold an IP address */
struct sockaddr_in cad;
int welcomeSocket, connectionSocket; /* socket descriptor */
Send line n=write(clientSocket, Sentence, strlen(Sentence)+1); struct hostent *ptrh; /* pointer to a host table entry */
to server
char clientSentence[128]; Create welcoming socket at port
char capitalizedSentence[128]; &
Read line n=read(clientSocket, modifiedSentence, sizeof(modifiedSentence)); Bind a local address
from server port = atoi(argv[1]);
printf("FROM SERVER: %s\n”,modifiedSentence); welcomeSocket = socket(PF_INET, SOCK_STREAM, 0);
memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
sad.sin_family = AF_INET; /* set family to Internet */
Close close(clientSocket); sad.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */
connection sad.sin_port = htons((u_short)port);/* set the port number */
} bind(welcomeSocket, (struct sockaddr *)&sad, sizeof(sad));
Example: C server (TCP), cont Socket programming with UDP
/* Specify the maximum number of clients that can be queued */
listen(welcomeSocket, 10)
Wait, on welcoming socket
while(1) { for contact by a client UDP: no “connection”
between client and server
connectionSocket=accept(welcomeSocket, (struct sockaddr *)&cad, &alen);
• no handshaking
n=read(connectionSocket, clientSentence, sizeof(clientSentence)); application viewpoint
• sender explicitly attaches
UDP provides unreliable transfer
/* capitalize Sentence and store the result in capitalizedSentence*/ IP address and port of
of groups of bytes (“datagrams”)
destination to each packet between client and server
n=write(connectionSocket, capitalizedSentence, strlen(capitalizedSentence)+1); • server must extract IP
address, port of sender
close(connectionSocket); from received packet
} Write out the result to socket
}
UDP: transmitted data may
End of while loop,
loop back and wait for be received out of order,
another client connection or lost
7
22-Sep-17
Example: C client (UDP)
Client/server socket interaction: UDP /* client.c */
void main(int argc, char *argv[])
Server (running on hostid) Client {
struct sockaddr_in sad; /* structure to hold an IP address */
create socket, int clientSocket; /* socket descriptor */
create socket,
port=x, for clientSocket = struct hostent *ptrh; /* pointer to a host table entry */
incoming request: DatagramSocket()
serverSocket =
DatagramSocket() char Sentence[128];
Create client socket,
Create, address (hostid, port=x, char modifiedSentence[128];
NO connection to server
send datagram request
read request from using clientSocket host = argv[1]; port = atoi(argv[2]);
serverSocket
clientSocket = socket(PF_INET, SOCK_DGRAM, 0);
write reply to
serverSocket
specifying client read reply from /* determine the server's address */
host address, clientSocket memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
port number close sad.sin_family = AF_INET; /* set family to Internet */
clientSocket sad.sin_port = htons((u_short)port);
ptrh = gethostbyname(host); /* Convert host name to IP address */
memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
Example: C server (UDP)
Example: C client (UDP), cont.
/* server.c */
Get void main(int argc, char *argv[])
input stream gets(Sentence); {
from user struct sockaddr_in sad; /* structure to hold an IP address */
struct sockaddr_in cad;
addr_len =sizeof(struct sockaddr); int serverSocket; /* socket descriptor */
Send line
n=sendto(clientSocket, Sentence, strlen(Sentence)+1, struct hostent *ptrh; /* pointer to a host table entry */
to server
(struct sockaddr *) &sad, addr_len);
char clientSentence[128]; Create welcoming socket at port
char capitalizedSentence[128]; &
Bind a local address
n=recvfrom(clientSocket, modifiedSentence, sizeof(modifiedSentence).
Read line port = atoi(argv[1]);
(struct sockaddr *) &sad, &addr_len);
from server
serverSocket = socket(PF_INET, SOCK_DGRAM, 0);
printf("FROM SERVER: %s\n”,modifiedSentence); memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
sad.sin_family = AF_INET; /* set family to Internet */
Close close(clientSocket); sad.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */
connection } sad.sin_port = htons((u_short)port);/* set the port number */
bind(serverSocket, (struct sockaddr *)&sad, sizeof(sad));
8
22-Sep-17
Example: C server (UDP), cont A Few Programming Notes:
while(1) { Receive messages from clients
Representing Packets
n=recvfrom(serverSocket, clientSentence, sizeof(clientSentence), 0
(struct sockaddr *) &cad, &addr_len ); 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/* capitalize Sentence and store the result in capitalizedSentence*/ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length | Checksum |
n=sendto(connectionSocket, capitalizedSentence, strlen(capitalizedSentence)+1,0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(struct sockaddr *) &cad, &addr_len); | Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
close(connectionSocket);
} Write out the result to socket Type: 4-byte integer
} Length: 2-byte integer
Checksum: 2-byte integer
End of while loop,
Address: 4-byte IP address
loop back and wait for
another client connection
A Few Programming Notes:
Building a Packet in a Buffer Socket Programming References
struct packet {
u_int32_t type;
u_int16_t length;
• Man page
u_int16_t checksum; – usage: man <function name>
u_int32_t address;
}; • Textbook
/* ================================================== */ – Stevens, Unix Network Programming, PHI
char buf[1024];
struct packet *pkt;
pkt = (struct packet*) buf;
pkt->type = htonl(1);
pkt->length = htons(2);
pkt->checksum = htons(3);
pkt->address = htonl(4);