0% found this document useful (0 votes)
17 views51 pages

Understanding TCP/IP Socket Programming

The document provides an overview of network programming, specifically focusing on the TCP/IP model and the use of sockets for client-server communication. It explains the socket API, including functions such as socket(), bind(), listen(), accept(), send(), and recv(), as well as the structure of socket addresses and the concept of network byte order. Additionally, it covers the implementation of a TCP concurrent server and the handling of interrupted system calls.

Uploaded by

Dinesh K
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views51 pages

Understanding TCP/IP Socket Programming

The document provides an overview of network programming, specifically focusing on the TCP/IP model and the use of sockets for client-server communication. It explains the socket API, including functions such as socket(), bind(), listen(), accept(), send(), and recv(), as well as the structure of socket addresses and the concept of network byte order. Additionally, it covers the implementation of a TCP concurrent server and the handling of interrupted system calls.

Uploaded by

Dinesh K
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

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

You might also like