Network Programming
1
client-server
TCP/IP Model
TCP/IP
• TCP/IP does not include an API
definition.
• There are a variety of APIs for use with
TCP/IP:
– Sockets
– TLI, XTI
– Winsock
– MacTCP
Telephone Analogy
Telephone Analogy
Both the user must have a telephone
A unique phone number is assigned to each
user
Turn on ringer to listen for a caller
Caller lifts the telephone and dials the
number
Receiver picks the phone when telephone
rings
Both user talks to each other
Hang up the phone when done
Network application
Network application has follows
An endpoint(telephone) for communication must be
created on both ends
An address(phone no) is assigned to both ends to
distinguish them from the rest of the network
One of the end points(caller) initiate a connection to
the other
The other end(receiver) point waits for the
communication to start
Once the connection has been made, data is
exchanged(talk)
Once the data has been exchanged the end points
are closed(hang up)
Socket functions
Socket – creates end points for
communication
Bind - Assigns unique telephone
number
Listen - Turn on ringer
Connect – Dial a number
Accept - Receive a call
send/recv/write/read/sendfrom/recvfrom -
talk
Close - hang up
Socket API – TCP
Application
9
Socket
• A socket is an abstract representation of a communication endpoint.
• Socket is 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
• Sockets work with Unix I/O services just like files, pipes & FIFOs.
• In Unix jargon, a socket is a file descriptor – an integer associated with
an open file
• Sockets (obviously) have special needs over files:
• establishing a connection
• specifying communication endpoint addresses
Socket Descriptor Data
Structure
Creating a Socket
• int socket(int family,int type,int
proto);
• family specifies the protocol family
(AF_INET for TCP/IP).
• type specifies the type of service
(SOCK_STREAM, SOCK_DGRAM).
• protocol specifies the specific protocol
(usually 0, which means the default).
Socket protocol
socket()
The socket() system call returns a
socket descriptor (small integer) or -1
on error.
socket() allocates resources needed
for a communication endpoint - but it
does not deal with endpoint addressing.
Necessary Background Information:
POSIX data types
int8_t signed 8bit int
uint8_t unsigned 8 bit int
int16_t signed 16 bit int
uint16_t unsigned 16 bit int
int32_t signed 32 bit int
uint32_t unsigned 32 bit int
u_char, u_short, u_int, u_long
More POSIX data types
sa_family_t address family
socklen_t length of struct
in_addr_t IPv4 address
in_port_t IP port number
Specifying an Endpoint
Address
• Remember that the sockets API is
generic.
• There must be a generic way to specify
endpoint addresses.
• TCP/IP requires an IP address and a
port number for each endpoint address.
• Other protocol suites (families) may use
other schemes.
Generic socket addresses
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
};
• sa_family specifies the address type.
• sa_data specifies the address value.
• sa_len length of this structure
struct sockaddr_in (IPv4)
struct sockaddr_in {
uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
A special kind of sockaddr structure – used for
IPV4 sockets
struct in_addr
struct in_addr {
in_addr_t s_addr;
};
Byte Order
Network Byte Order
• Network communication uses Bigendian
style, also known as Network Byte
Order (NBO)
• All values stored in a sockaddr_in
must be in network byte order.
• sin_port a TCP/IP port number.
• sin_addr an IP address.
Network Byte Order Functions
‘h’ : host byte order ‘n’ : network byte order
‘s’ : short (16bit) ‘l’ : long (32bit)
uint16_t htons(uint16_t);
uint16_t ntohs(uint_16_t);
uint32_t htonl(uint32_t);
uint32_t ntohl(uint32_t);
Assigning an address to a
socket
• The bind() system call is used to assign
an address to an existing socket.
int bind( int sockfd,
const struct sockaddr *myaddr,
int addrlen);
const!
• bind returns 0 if successful or -1 on error.
bind()
calling bind() assigns the address
specified by the sockaddr structure to
the socket descriptor.
You can give bind() a sockaddr_in
structure:
bind( mysock,
(struct sockaddr*) &myaddr,
sizeof(myaddr) );
bind() Example
int mysock,err;
struct sockaddr_in myaddr;
mysock = socket(PF_INET,SOCK_STREAM,0);
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons( portnum );
myaddr.sin_addr = htonl( ipaddress);
err=bind(mysock, (sockaddr *) &myaddr,
sizeof(myaddr));
bind()
IP address port result
wildcard 0 kernel chooses IP addr and port
wildcard nonzero kernel chooses IP, process specifies port
local IP addr 0 process specifies IP, kernel chooses port
local IP addr nonzero process specifies IP and port
Uses for bind()
There are a number of uses for bind():
– Server would like to bind to a well known
address (port number).
– Client can bind to a specific port.
– Client can ask the O.S. to assign any
available port number.
IPv4 Address Conversion
int inet_aton( char *, struct in_addr *);
Convert ASCII dotted-decimal IP address to
network byte order 32 bit value. Returns 1
on success, 0 on failure.
char *inet_ntoa(struct in_addr);
Convert network byte ordered value to
ASCII dotted-decimal (a string).
About TCP and UDP Ports
• TCP and UDP Ports are 16-bit numbers.
• They are of three types:
- Well-known Ports (0-1023: Controlled by the
IANA)
- Registered Ports (1024-49159) and
- Ephemeral / Dynamic Ports (49152-65535).
(RFC 1700 shows a list suggested initially)
• FTP over TCP uses 21 whereas TFTP over UDP uses
69 for instance.
31
connect()
int connect(int sockfd, const struct sockaddr
*servaddr, socklen_t addrlen);
• sockfd is socket descriptor from socket()
• servaddr is a pointer to a structure with:
• port number and IP address
• must be specified (unlike bind())
• addrlen is length of structure
• client doesn’t need bind()
• OS will pick ephemeral port
• returns socket descriptor if ok, -1 on error
listen()
int listen(int sockfd, int backlog);
• sockfd is socket descriptor from socket()
• backlog is maximum number of connections
that the server should queue for this socket
• historically 5
• rarely above 15 on a even moderate Web server!
accept()
int accept(int sockfd, struct sockaddr
*cliaddr, socklen_t *addrlen);
• sockfd is socket descriptor from socket()
• cliaddr and addrlen return protocol address
from client
• returns brand new descriptor, created by OS
read() and write()
int read (int sockfd, void *buff, size_t
mbytes);
int write (int sockfd, void *buff, size_t
mbytes);
• Reading and writing packets
• Both are system calls
send ( ) and recv ( )
Functions
These two functions are for communicating over stream
sockets or connected datagram sockets.
int send(int sockfd, const void *msg, int len, int flags);
– sockfd is the socket descriptor you want to send
data to (returned by socket() or got from accept())
– msg is a pointer to the data you want to send
– len is the length of that data in bytes
– set flags to 0 for now
– send() returns the number of bytes actually sent
(may be less than the number you told it to send)
or -1 on error
36
send ( ) and recv ( )
Functions
int recv(int sockfd, void *buf, int len, int flags);
– sockfd is the socket descriptor to read from
– buf is the buffer to read the information into
– len is the maximum length of the buffer
– set flags to 0 //default behaviour
recv() returns the number of bytes actually read into the
buffer or -1 on error
If recv() returns 0, the remote side has closed
connection on you
37
close()
int close(int sockfd);
• sockfd is socket descriptor from socket()
• closes socket for reading/writing
• returns (doesn’t block)
• attempts to send any unsent data
• Returns -1 if error
getsockname()
TCP client that does not call bind, getsockname
returns the local IP address and local port number
assigned to the connection by the kernel.
After calling bind with a port number of 0,
getsockname returns the local port number that was
assigned.
getsockname can be called to obtain the address
family of a socket
In a TCP server that binds the wildcard IP address,
once a connection is established with a client (accept
returns successfully), the server can call
getsockname to obtain the local IP address assigned
to the connection.
getpeername()
When a server is execed by the process
that calls accept, the only way the
server can obtain the identity of the
client is to call getpeername
inetd server works by execing the
respective server’s image
TCP Echo Client
int bzero(&servaddr, sizeof(servaddr));
main(int argc, char **argv) servaddr.sin_family = AF_INET;
{ servaddr.sin_port =
int sockfd; htons(SERV_PORT);
struct sockaddr_in servaddr; Inet_pton(AF_INET, argv[1],
&servaddr.sin_addr);
if (argc != 2)
Connect(sockfd, (SA *) &servaddr,
err_quit("usage: tcpcli
sizeof(servaddr));
<IPaddress>");
str_cli(stdin, sockfd);
sockfd = Socket(PF_INET,
SOCK_STREAM, 0); exit(0);
}
str_cli function
2 void
3 str_cli(FILE *fp, int sockfd)
4{
5 char sendline[MAXLINE], recvline[MAXLINE];
6 while (Fgets(sendline, MAXLINE, fp) != NULL) {
7 Write(sockfd, sendline, strlen (sendline));
8 if (Read(sockfd, recvline, MAXLINE) == 0)
9 err_quit("str_cli: server terminated prematurely");
10 Fputs(recvline, stdout);
11 }
12 }
TCP Concurrent Server
TCP Concurrent Server
2 int 15 Listen(listenfd, LISTENQ);
3 main(int argc, char **argv) 16 for ( ; ; ) {
4{ 17 clilen = sizeof(cliaddr);
5 int listenfd, connfd; 18 connfd = Accept(listenfd, (SA *)
6 pid_t childpid; &cliaddr, &clilen);
7 socklen_t clilen;
8 struct sockaddr_in cliaddr, servaddr; 19 if ( (childpid = Fork()) == 0) { /* child
process */
9 listenfd = Socket (AF_INET, 20 Close(listenfd); /* close
listening socket */
SOCK_STREAM, 0);
21 str_echo(connfd); /* process the
request */
10 bzero(&servaddr, sizeof(servaddr));
22 exit (0);
11 servaddr.sin_family = AF_INET;
23 }
12 servaddr.sin_addr.s_addr = htonl
(INADDR_ANY); 24 Close(connfd); /* parent
closes connected socket */
13 servaddr.sin_port = htons
25 }
(SERV_PORT);
26 }
14 Bind(listenfd, (SA *) &servaddr,
sizeof(servaddr));
str_echo function
void
str_echo(int sockfd)
{
ssize_t n;
char buf[MAXLINE];
again:
while ( (n = read(sockfd, buf, MAXLINE)) > 0)
Write(sockfd, buf, n);
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}
TCP Concurrent Server
Handling zombies
– while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
in SIGCHLD signal handler
Handling interrupted system calls
– when writing network programs that catch signals,
we must be cognizant of interrupted system calls,
and we must handle them
– Slow system call is any system call that can block
forever
Handling interrupted system calls
for ( ; ; ) {
clilen = sizeof (cliaddr);
if ( (connfd = accept (listenfd, (SA *)
&cliaddr, &clilen)) < 0) {
if (errno == EINTR)
continue; /* back to for () */
else
err_sys ("accept error");
}
sendto ( ) and recvfrom ( )
Functions
int sendto(int sockfd, const void *msg, int len, int flags, const struct
sockaddr *to, int tolen);
– to is a pointer to a struct sockaddr which contains
the destination IP and port
– tolen is sizeof(struct sockaddr)
int recvfrom(int sockfd, void *buf, int len, int flags, struct sockaddr
*from, int *fromlen);
– from is a pointer to a local struct sockaddr that will
be filled with IP address and port of the originating
machine
– fromlen will contain length of address stored in from
48
select ( ) Function
An application system can multiplex I/O requests among
multiple sockets by using select.
fd_set readmask, writemask, exceptmask; struct timeval
timeout; ... select(nfds, &readmask, &writemask,
&exceptmask, &timeout);
The select call takes three I/O descriptor sets as
arguments:
- the set of file descriptors on which the caller
wishes to be able to read data
- the set of descriptors to which data is to be
written
- any pending exceptional conditions
49
Socket API – UDP Application
50
Thank You