0% found this document useful (0 votes)
62 views

TCP/IP Sockets in C: Practical Guide For Programmers Computer Chat

1. The document discusses how TCP/IP sockets allow computers to communicate over the Internet using protocols like TCP and UDP. It explains key concepts like IP addresses, ports, sockets, and the client-server model of communication. 2. TCP provides reliable, ordered delivery of data between applications through mechanisms like checksums, flow control and congestion control. UDP provides a simpler datagram service without these guarantees. 3. Sockets provide a generic interface for applications to communicate over different protocols like TCP and UDP, identifying the endpoint through address and port. Clients initiate connections while servers passively wait to accept incoming requests and respond.

Uploaded by

kniffe
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
62 views

TCP/IP Sockets in C: Practical Guide For Programmers Computer Chat

1. The document discusses how TCP/IP sockets allow computers to communicate over the Internet using protocols like TCP and UDP. It explains key concepts like IP addresses, ports, sockets, and the client-server model of communication. 2. TCP provides reliable, ordered delivery of data between applications through mechanisms like checksums, flow control and congestion control. UDP provides a simpler datagram service without these guarantees. 3. Sockets provide a generic interface for applications to communicate over different protocols like TCP and UDP, identifying the endpoint through address and port. Clients initiate connections while servers passively wait to accept incoming requests and respond.

Uploaded by

kniffe
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

TCP/IP Sockets in C:

Practical Guide for Computer Chat


Programmers ! How do we make computers talk?

Michael J. Donahoo
Kenneth L. Calvert

Morgan Kaufmann Publisher


$14.95 Paperback
! How are they interconnected?

Internet Protocol (IP)

Internet Protocol (IP) IP Address


! Datagram (packet) protocol ! 32-bit identifier (IPv4, IPv6=128 bits)
! Best-effort service ! Dotted-quad: 192.118.56.25
! Loss ! www.mkp.com -> 167.208.101.28
! Reordering ! Identifies a host interface (not a host)
! Duplication
! Delay
! Host-to-host delivery
192.18.22.13 209.134.16.123

Transport Protocols Ports


Best-effort not sufficient! Identifying the ultimate destination
! Add services on top of IP ! IP addresses identify hosts
! User Datagram Protocol (UDP) ! Host has many applications
Data checksum
Ports (16-bit identifier) 1-65,535
!
!
! Best-effort
! Transmission Control Protocol (TCP) Application WWW E-mail Telnet
! Data checksum
Port 80 25 23
! Reliable byte-stream delivery
! Flow and congestion control
192.18.22.13
Socket Sockets
! Identified by protocol and local/remote
How does one speak TCP/IP? address/port
! Applications may refer to many sockets
! Sockets accessed by many applications
! Sockets provides interface to TCP/IP
! Generic interface for many protocols

TCP/IP Sockets Specifying Addresses


! struct sockaddr
! mySock = socket(family, type, protocol); {
Generic

unsigned short sa_family; /* Address family (e.g., AF_INET) */


! TCP/IP-specific sockets };
char sa_data[14]; /* Protocol-specific address information */

Family Type Protocol


! struct sockaddr_in
TCP SOCK_STREAM IPPROTO_TCP {
PF_INET unsigned short sin_family; /* Internet protocol (AF_INET) */
UDP SOCK_DGRAM IPPROTO_UDP unsigned short sin_port; /* Port (16-bits) */
IP Specific

struct in_addr sin_addr; /* Internet address (32-bits) */


char sin_zero[8]; /* Not used */
! Socket reference };
struct in_addr
! File (socket) descriptor in UNIX {
unsigned long s_addr; /* Internet address (32-bits) */
};

Clients and Servers TCP Client/Server Interaction


! Client: Initiates the connection
Server starts by getting ready to receive client connections…
Client: Bob Server: Jane

“Hi. I’m Bob.” Server


Client
Create a TCP socket 1. Create a TCP socket
“Hi, Bob. I’m Jane” 1.
2. Assign a port to socket
2. Establish connection
3. Communicate 3. Set socket to listen
“Nice to meet you, Jane.” 4. Repeatedly:
4. Close the connection
a. Accept new connection
Communicate
Server: Passively waits to respond
b.
!
c. Close the connection
TCP Client/Server Interaction TCP Client/Server Interaction
echoServAddr.sin_family = AF_INET; /* Internet address family */
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);/* Any incoming interface */
/* Create socket for incoming connections */ echoServAddr.sin_port = htons(echoServPort); /* Local port */
if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError("socket() failed"); if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
DieWithError("bind() failed");

Client Server Client Server


1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket
2. Establish connection 2. Bind socket to a port 2. Establish connection 2. Bind socket to a port
3. Communicate 3. Set socket to listen 3. Communicate 3. Set socket to listen
4. Close the connection 4. Repeatedly: 4. Close the connection 4. Repeatedly:
a. Accept new connection a. Accept new connection
b. Communicate b. Communicate
c. Close the connection c. Close the connection

TCP Client/Server Interaction TCP Client/Server Interaction


for (;;) /* Run forever */
/* Mark the socket so it will listen for incoming connections */ {
if (listen(servSock, MAXPENDING) < 0) clntLen = sizeof(echoClntAddr);
DieWithError("listen() failed");
if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen)) < 0)
DieWithError("accept() failed");

Client Server Client Server


1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket
2. Establish connection 2. Bind socket to a port 2. Establish connection 2. Bind socket to a port
3. Communicate 3. Set socket to listen 3. Communicate 3. Set socket to listen
4. Close the connection 4. Repeatedly: 4. Close the connection 4. Repeatedly:
a. Accept new connection a. Accept new connection
b. Communicate b. Communicate
c. Close the connection c. Close the connection

TCP Client/Server Interaction TCP Client/Server Interaction

Server is now blocked waiting for connection from a client Later, a client decides to talk to the server…

Client Server Client Server


1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket
2. Establish connection 2. Bind socket to a port 2. Establish connection 2. Bind socket to a port
3. Communicate 3. Set socket to listen 3. Communicate 3. Set socket to listen
4. Close the connection 4. Repeatedly: 4. Close the connection 4. Repeatedly:
a. Accept new connection a. Accept new connection
b. Communicate b. Communicate
c. Close the connection c. Close the connection
TCP Client/Server Interaction TCP Client/Server Interaction
echoServAddr.sin_family = AF_INET; /* Internet address family */
echoServAddr.sin_addr.s_addr = inet_addr(servIP); /* Server IP address */
/* Create a reliable, stream socket using TCP */ echoServAddr.sin_port = htons(echoServPort); /* Server port */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError("socket() failed"); if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
DieWithError("connect() failed");

Client Server Client Server


1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket
2. Establish connection 2. Bind socket to a port 2. Establish connection 2. Bind socket to a port
3. Communicate 3. Set socket to listen 3. Communicate 3. Set socket to listen
4. Close the connection 4. Repeatedly: 4. Close the connection 4. Repeatedly:
a. Accept new connection a. Accept new connection
b. Communicate b. Communicate
c. Close the connection c. Close the connection

TCP Client/Server Interaction TCP Client/Server Interaction


echoStringLen = strlen(echoString); /* Determine input length */

/* Send the string to the server */ if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen)) < 0)


if (send(sock, echoString, echoStringLen, 0) != echoStringLen) DieWithError("accept() failed");
DieWithError("send() sent a different number of bytes than expected");

Client Server Client Server


1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket
2. Establish connection 2. Bind socket to a port 2. Establish connection 2. Bind socket to a port
3. Communicate 3. Set socket to listen 3. Communicate 3. Set socket to listen
4. Close the connection 4. Repeatedly: 4. Close the connection 4. Repeatedly:
a. Accept new connection a. Accept new connection
b. Communicate b. Communicate
c. Close the connection c. Close the connection

TCP Client/Server Interaction TCP Client/Server Interaction


/* Receive message from client */
if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0)
DieWithError("recv() failed"); close(sock); close(clntSocket)

Client Server Client Server


1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket 1. Create a TCP socket
2. Establish connection 2. Bind socket to a port 2. Establish connection 2. Bind socket to a port
3. Communicate 3. Set socket to listen 3. Communicate 3. Set socket to listen
4. Close the connection 4. Repeatedly: 4. Close the connection 4. Repeatedly:
a. Accept new connection a. Accept new connection
b. Communicate b. Communicate
c. Close the connection c. Close the connection
TCP Tidbits Closing a Connection
! Client knows server address and port ! close() used to delimit communication
! No correlation between send() and recv() ! Analogous to EOF

Client Server Client Server


send(“Hello Bob”) send(string)
recv(buffer)
recv() -> “Hello ”
while (not received entire string) while(client has not closed connection)
recv() -> “Bob”
recv(buffer) send(buffer)
send(“Hi ”) send(buffer) recv(buffer)
send(“Jane”)
recv() -> “Hi Jane” close(socket)
close(client socket)

TCP/IP Byte Transport


TCP/IP protocols transports bytes
Constructing Messages
!

Application Application
byte stream byte stream
Here are some I’ll pass
…beyond simple strings bytes. I don’t
know what
these to
TCP/IP TCP/IP the app. It
they mean. knows
what to do.

! Application protocol provides semantics

Application Protocol Primitive Types


! Encode information in bytes ! String
! Sender and receiver must agree on ! Character encoding: ASCII, Unicode, UTF
semantics ! Delimit: length vs. termination character
! Data encoding
0 77 0 111 0 109 0 10
! Primitive types: strings, integers, and etc.
! Composed types: message with fields M o m \n

3 77 111 109
Primitive Types Primitive Types
! Integer ! Integer
! Strings of character encoded decimal digits ! Native representation
49 55 57 57 56 55 48 10 Little-Endian 0 0 92 246 4-byte
‘1’ ‘7’ ‘9’ ‘9’ ‘8’ ‘7’ ‘0’ \n 23,798 two’s-complement
integer
Big-Endian 246 92 0 0
! Advantage: 1. Human readable
! Network byte order (Big-Endian)
2. Arbitrary size
! Use for multi-byte, binary data exchange
! Disadvantage: 1. Inefficient
! htonl(), htons(), ntohl(), ntohs()
2. Arithmetic manipulation

“Beware the bytes of padding”


Message Composition -- Julius Caesar, Shakespeare
! Message composed of fields ! Architecture alignment restrictions
! Fixed-length fields ! Compiler pads structs to accommodate

integer short short struct tst {


short x;
int y; x [pad] y z [pad]
! Variable-length fields short z;
};
M i k e 1 2 \n ! Problem: Alignment restrictions vary
! Solution: 1) Rearrange struct members
2) Serialize struct by-member

TCPEchoClient.c

#include <stdio.h> /* for printf() and fprintf() */ servIP = argv[1]; /* First arg: server IP address (dotted quad) */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */ echoString = argv[2]; /* Second arg: string to echo */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
#include <stdlib.h> /* for atoi() */ if (argc == 4)
#include <string.h> /* for memset() */ echoServPort = atoi(argv[3]); /* Use given port, if any */
#include <unistd.h> /* for close() */ else
echoServPort = 7; /* 7 is the well-known port for the echo service */
#define RCVBUFSIZE 32 /* Size of receive buffer */
/* Create a reliable, stream socket using TCP */
void DieWithError(char *errorMessage); /* Error handling function */ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError("socket() failed");
int main(int argc, char *argv[])
{ /* Construct the server address structure */
int sock; /* Socket descriptor */ memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
struct sockaddr_in echoServAddr; /* Echo server address */ echoServAddr.sin_family = AF_INET; /* Internet address family */
unsigned short echoServPort; /* Echo server port */ echoServAddr.sin_addr.s_addr = inet_addr(servIP); /* Server IP address */
char *servIP; /* Server IP address (dotted quad) */ echoServAddr.sin_port = htons(echoServPort); /* Server port */
char *echoString; /* String to send to echo server */
char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */ /* Establish the connection to the echo server */
unsigned int echoStringLen; /* Length of string to echo */ if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv() DieWithError("connect() failed");
and total bytes read */
echoStringLen = strlen(echoString); /* Determine input length */
if ((argc < 3) || (argc > 4)) /* Test for correct number of arguments */
{ /* Send the string to the server */
fprintf(stderr, "Usage: %s <Server IP> <Echo Word> [<Echo Port>]\n", if (send(sock, echoString, echoStringLen, 0) != echoStringLen)
argv[0]); DieWithError("send() sent a different number of bytes than expected");
exit(1);
}
TCPEchoServer.c

/* receive the same string back from the server */ #include <stdio.h> /* for printf() and fprintf() */
totalBytesRcvd = 0; #include <sys/socket.h> /* for socket(), bind(), and connect() */
printf("Received: "); /* Setup to print the echoed string */ #include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */
while (totalBytesRcvd < echoStringLen) #include <stdlib.h> /* for atoi() */
{ #include <string.h> /* for memset() */
/* Receive up to the buffer size (minus 1 to leave space for #include <unistd.h> /* for close() */
a null terminator) bytes from the sender */
if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0) #define MAXPENDING 5 /* Maximum outstanding connection requests */
DieWithError("recv() failed or connection closed prematurely");
totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */ void DieWithError(char *errorMessage); /* Error handling function */
echoBuffer[bytesRcvd] = '\0'; /* Terminate the string! */ void HandleTCPClient(int clntSocket); /* TCP client handling function */
printf(echoBuffer); /* Print the echo buffer */
} int main(int argc, char *argv[])
{
printf("\n"); /* Print a final linefeed */ int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
close(sock); struct sockaddr_in echoServAddr; /* Local address */
exit(0); struct sockaddr_in echoClntAddr; /* Client address */
} unsigned short echoServPort; /* Server port */
unsigned int clntLen; /* Length of client address data structure */
void DieWithError(char *errorMessage)
{ if (argc != 2) /* Test for correct number of arguments */
perror(errorMessage); {
exit(1); fprintf(stderr, "Usage: %s <Server Port>\n", argv[0]);
} exit(1);
}

echoServPort = atoi(argv[1]); /* First arg: local port */

/* Create socket for incoming connections */


if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) for (;;) /* Run forever */
DieWithError("socket() failed"); {
/* Set the size of the in-out parameter */
/* Construct local address structure */ clntLen = sizeof(echoClntAddr);
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sin_family = AF_INET; /* Internet address family */ /* Wait for a client to connect */
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ if ((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr,
echoServAddr.sin_port = htons(echoServPort); /* Local port */ &clntLen)) < 0)
DieWithError("accept() failed");
/* Bind to the local address */
if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) /* clntSock is connected to a client! */
DieWithError("bind() failed");
printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));
/* Mark the socket so it will listen for incoming connections */
if (listen(servSock, MAXPENDING) < 0) HandleTCPClient(clntSock);
DieWithError("listen() failed"); }
/* NOT REACHED */
}

Transport Protocols Transport Protocols


! Best-effort, host-to-host insufficient ! User Datagram Protocol (UDP)
! Transport protocols add services to IP ! Adds ports and data checksum to IP
! Best-effort
! Ports make end-to-end protocols
! Transmission Control Protocol (TCP)
Application WWW E-mail Telnet
! Adds ports and data checksum to IP
Port 80 25 23 ! Reliable byte-stream delivery
! Flow and congestion control
! Etc.
192.18.22.13
Socket Protocols TCP Client
! Protocol Family
1. Create a TCP socket using socket()
! PF_INET – Internet Protocol Family
! Protocol Type 2. Establish a connection to the server
using connect()
! SOCK_STREAM – Reliable byte-stream
! SOCK_DGRAM – Best-effort datagram 3. Communicate using send() and
recv()
! Protocol
! IPPROTO_TCP
4. Close the connection with close()
! IPPROTO_UDP

TCP Server Protocols


1. Create a TCP socket using socket() ! We want to make computers “talk”
2. Assign a port number to the socket with
bind() ! Protocol: Agreement on exchange
3. Tell the system to allow connections to be Bob Jane
made to that port, using listen()
4. Repeatedly do the following: “Hi. I’m Bob.”
a. Call accept() to get a new socket for each
“Hi, Bob. I’m Jane”
client connection.
b. Communicate with the client via that new
socket, using send() and recv() “Nice to meet you, Jane.”
c. Close the client connection using close()

for (;;) /* Run forever */


{
clntSock = AcceptTCPConnection(servSock);
TCPEchoServer-Fork.c /* Fork child process and report any errors */
if ((processID = fork()) < 0)
#include "TCPEchoServer.h" /* TCP echo server includes */ DieWithError("fork() failed");
#include <sys/wait.h> /* for waitpid() */ else if (processID == 0) /* If this is the child process */
{
int main(int argc, char *argv[]) close(servSock); /* Child closes parent socket */
{ HandleTCPClient(clntSock);
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */ exit(0); /* Child process terminates */
unsigned short echoServPort; /* Server port */ }
pid_t processID; /* Process ID from fork() */
unsigned int childProcCount = 0; /* Number of child processes */ printf("with child process: %d\n", (int) processID);
close(clntSock); /* Parent closes child socket descriptor */
if (argc != 2) /* Test for correct number of arguments */ childProcCount++; /* Increment number of outstanding child processes */
{
fprintf(stderr, "Usage: %s <Server Port>\n", argv[0]); while (childProcCount) /* Clean up all zombies */
exit(1); {
} processID = waitpid((pid_t) -1, NULL, WNOHANG); /* Non-blocking wait */
if (processID < 0) /* waitpid() error? */
echoServPort = atoi(argv[1]); /* First arg: local port */ DieWithError("waitpid() failed");
else if (processID == 0) /* No zombie to wait on */
servSock = CreateTCPServerSocket(echoServPort); break;
else
childProcCount--; /* Cleaned up after a child */
}
}
}
#define MAXPENDING 5 /* Maximum outstanding connection requests */
#include <stdio.h> /* for printf() */
void DieWithError(char *errorMessage); /* Error handling function */ #include <sys/socket.h> /* for accept() */
#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */
int CreateTCPServerSocket(unsigned short port)
{ void DieWithError(char *errorMessage); /* Error handling function */
int sock; /* socket to create */
struct sockaddr_in echoServAddr; /* Local address */ int AcceptTCPConnection( int servSock )
{
/* Create socket for incoming connections */ int clntSock; /* Socket descriptor for client */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) struct sockaddr_in echoClntAddr; /* Client address */
DieWithError("socket() failed"); unsigned int clntLen; /* Length of client address data structure */

/* Construct local address structure */ /* Set the size of the in-out parameter */
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */ clntLen = sizeof(echoClntAddr);
echoServAddr.sin_family = AF_INET; /* Internet address family */
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ /* Wait for a client to connect */
echoServAddr.sin_port = htons(port); /* Local port */ if ((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr,
&clntLen)) < 0)
/* Bind to the local address */ DieWithError("accept() failed");
if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
DieWithError("bind() failed"); /* clntSock is connected to a client! */

/* Mark the socket so it will listen for incoming connections */ printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));
if (listen(sock, MAXPENDING) < 0)
DieWithError("listen() failed"); return clntSock;
}
return sock;
}

Resources/References

! http://cs.ecs.baylor.edu/~donahoo/practical/C
Sockets
! http://www.ecst.csuchico.edu/~beej/guide
! Network programming
! Unix Interprocess communication

You might also like