TCP/IP Sockets in C: Practical Guide For Programmers Computer Chat
TCP/IP Sockets in C: Practical Guide For Programmers Computer Chat
Michael J. Donahoo
Kenneth L. Calvert
Server is now blocked waiting for connection from a client Later, a client decides to talk to the server…
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.
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
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);
}
/* 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