1.09k likes | 1.46k Views
Introduction to Programming in C with Sockets. George Blank. Warning.
E N D
Introduction to Programming in C with Sockets George Blank
Warning • You should not assume that an example in this presentation is complete. Items may have been selected for illustration. It is best to get your code examples directly from the textbook and modify them to work. Use the lectures to understand the general principles. • There is a trouble shooting section near the end of this lecture.
Socket Functions • socket: create a descriptor for use in network communication. int socket(int family, int type, int protocol) • connect: connect to a remote peer (used by client) int connect(int sockfd, struct sockaddr *addr, int addrlen); • write: send outgoing data across a connection. int write(int sockfd, void *buf, int count); • read: acquire incoming data from a connection. int read(int sockfd, void *buf, int count);
Socket Functions (Cont’d) • close: terminate communication and deallocate a descriptor. • bind: bind a local IP address and protocol number to a socket. • listen: place the socket in passive mode and set the number of incoming TCP connections the system will enqueue. • accept: accept the next incoming connection (by server).
Creating A Socket • The socket system call establishes the end point of a communications link. sd= socket(format, type, protocol); format = AF_UNIX, AF_INET, PF_INET or AF_IMPLINK type = SOCK_STREAM, SOCK_DGRAM or SOCK_RAW protocol = IPPROTO_TCP _UDP _ICMPor_RAW • The socket descriptor sd is then used in system calls. • Close sockets with close()
Data Conversion Functions • The functions htons, ntohs, htonl, and ntohl are used to convert binary integers between the host’s native byte order and the network standard byte order. • This makes the source code portable to any machine, independent of the the native byte order
Client Architecture • Simpler than servers • Most clients do not explicitly handle concurrent interactions with multiple servers. • Most client software executes as a conventional program. • Clients, unlike servers, do not require special privileged ports. • Most clients rely on OS for security.
Socket Address Structure struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; };
Domain Name Structure struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* host’s alias names */ int h_addrtype; /* address type */ char **h_addr_list; /*list of addresses from name server */ };
Example: Char *host = “cis.njit.edu”; struct hostent *hp; … hp = gethostbyname(host); “inet_addr()” takes an ASCII string that contains a dotted decimal address and returns the equivalent IP address in binary.
Service Structure struct servent { char *s_name; /* service name */ char **s_aliases; /* alias list */ int s_port; /* port number */ char *s_proto; /* protocol to use */ };
Example: struct servent *sp; .. sp = getservbyname(“smtp”, “tcp”); sp->s_port has the port number.
The Protocol Structure struct protoent { char *p_name; /* official protocol name */ char **p_aliases; /* allowed aliases */ int p_proto; /* official protocol number */ }; Example: struct protoent *pp; pp = getprotobyname(“udp”);
Note on Examples • The code in these examples is from the Winsock version of the Comer and Stevens text. • I do not recommend using code from the slides. Use the text instead, and make sure that you use a Winsock or Unix version of the text as needed in your environment. • Note that the Algorithms are repeated several times.
TCP Client AlgorithmComer and Stevens, Algorithm 6.1 • Find IP address and protocol port number on server • Allocate a socket • Allow TCP to allocate an arbitrary local port • Connect the socket to the server • Send requests and receive replies • Close the connection
Program #1 • A TCP client that accesses the daytime service. • As soon as a new connection arrives, the server forms a text string that contains the current date and time, sends the string, and then closes the connection. • It operates on protocol port 13. • Comer, Chapter 7 (Winsock, p. 86, Linux p. 89)
#include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h>
#define INADDR_NONE 0xffffffff extern int errno; int error( char *msg); #define LINELEN 128 int main(int argc, char *argv[]){ char *host ; char *service = "daytime"; /* default service port */ char buf[LINELEN+1]; /* buffer for one line of text */ int n; /* read count */ struct hostent *hp; /* pointer to host information entry*/
struct servent *sp; /* pointer to service information entry*/ struct protoent *pp; /* pointer to protocol information entry*/ struct sockaddr_in sin; /* an Internet endpoint address */ int s; /* socket descriptor and socket type */ if (argc != 2) { fprintf(stderr, "usage: %s host\n", argv[0]); exit(1); } host = argv[1];
memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; /* Map service name to port number */ if ( sp = getservbyname(service, "tcp") ) sin.sin_port = sp->s_port; else error("can't get service entry\n");
/* Map host name to IP address, allowing for dotted decimal */ if ( hp = gethostbyname(host) ) memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) error("can't get host entry\n"); /* Map transport prot. name to prot. num. */ if ( (pp = getprotobyname("tcp")) == 0) error("can't get protocol entry\n");
/* Allocate a socket */ s = socket(PF_INET, SOCK_STREAM, pp->p_proto); if (s < 0) error("can't create socket: \n"); /* Connect the socket */ if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) error("can't connect to host\n");
while( (n = read(s, buf, LINELEN)) > 0) { buf[n] = '\0'; fputs(buf, stdout); } exit(0); } int error(char *format){ fprintf(stderr, format); exit(1); }
UDP Client AlgorithmComer and Stevens, Algorithm 6.2 • Find IP address and protocol port number on server • Allocate a socket • Allow UDP to allocate an arbitrary local port • Specify the server • Send requests and receive replies • Close the socket
Program #2 • This is the UDP version of program #1. • It requires the client to send an (arbitrary) request. • Upon receiving the datagram, the server formats the current date and time, and sends a datagram back to the client. • Comer, Chapter 7 (Winsock, p. 90, Linux p. 92)
#include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h>
#define INADDR_NONE 0xffffffff extern int errno; #define UNIXEPOCH 2208988800 int error( char *msg); int main(int argc, char *argv[]){ char *host ; char *service = "time"; /* default service port */ time_t now; /* 32-bit integer for time */
int n; /* read count*/ struct hostent *hp; /* ptr to host info entry*/ struct servent *sp; /* ptr to service info entry*/ struct protoent *pp; /* ptr to prot. info entry*/
struct sockaddr_in sin; /* an Internet endpoint addr */ int s; /* socket desc.and socket type */ if (argc != 2) { fprintf(stderr,"usage: %s host\n", argv[0]); exit(1); } host = argv[1];
memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; /* Map service name to port num */ if ( sp = getservbyname (service, "udp") ) sin.sin_port = sp->s_port;\ else error("can't get service entry\n");
/* Map host name to IP address, allowing for dotted decimal */ if ( hp = gethostbyname(host) ) memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); else if( (sin.sin_addr.s_addr = inet_addr(host))== INADDR_NONE) error("can't get host entry");
/* Map transport protocol name to protocol number */ if ( (pp = getprotobyname("udp")) == 0) error("can't get prot. entry\n"); /* Allocate a socket */ s = socket(PF_INET, SOCK_DGRAM, pp->p_proto); if (s < 0) error("can't create socket: \n");
/* Connect the socket */ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) error("can't connect to host\n");
write(s, "Hello",strlen("Hello")); n = read(s, (char *)&now, sizeof(now)); if( n < 0 ) error("read failed\n"); now = ntohl((u_long)now); now -= UNIXEPOCH; printf("%s", ctime(&now)); exit(0); }
TCP Iterative Server AlgorithmComer and Stevens, Algorithm 8.1 • Create a socket and bind to the well known address for the service offered • Place socket in passive mode • Accept next connection request and obtain a new socket • Repeatedly receive requests and send replies • When client is done, close the connection and return to waiting for connection requests
UDP Iterative Server AlgorithmComer and Stevens, Algorithm 8.2 • Create a socket and bind to the well known address for the service offered • Repeatedly receive requests and send replies
Program #3 • Echo is a standard service for both TCP and and UDP. • Comer, Chapter 7 (Winsock, p. 92, Linux p. 94) • An Echo server is often used by network managers to test reachability, identify routing problems, and debug protocols.
#include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define INADDR_NONE 0xffffffff
extern int errno; int error( char *msg); #define LINELEN 128 int main(int argc, char *argv[]) { char *host ; /* default service port */ char *service = "echo"; char buf[LINELEN+1]; /* buffer for one line of text */ int n; /* read count */
struct hostent *hp; /* pointer to host information entry */ struct servent *sp; /* pointer to service information entry*/ struct protoent *pp; /* pointer to protocol info entry*/ struct sockaddr_in sin; /* an Internet endpoint address */ int s; /* socket descriptor and socket type*/ int inchars, outchars;
if (argc != 2) { fprintf(stderr, "usage: %s host\n", argv[0]); exit(1); } host = argv[1]; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
/* Map service name to port number */ if ( sp = getservbyname(service, "tcp") ) sin.sin_port = sp->s_port; else error("can't get service entry\n"); /* Map host name to IP address, allowing for dotted decimal */ if ( hp = gethostbyname(host) ) memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) error("can't get host entry\n");
/* Map transport prot. name to prot. num */ if ( (pp = getprotobyname("tcp")) == 0) error("can't get protocol entry\n"); /* Allocate a socket */ s = socket(PF_INET, SOCK_STREAM, pp->p_proto); if (s < 0) error("can't create socket: \n"); /* Connect the socket */ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) error("can't connect to host\n");
while( fgets(buf, sizeof(buf), stdin)) { buf[LINELEN] = '\0'; outchars = strlen(buf); write(s, buf, outchars); for( inchars=0; inchars<outchars; inchars+=n ){ n = read(s, &buf[inchars], outchars - inchars); if( n < 0 ) error("Socket read failed\n"); } fputs(buf, stdout); } exit(0); }
UDP Client AlgorithmComer and Stevens, Algorithm 6.2 • Find IP address and protocol port number on server • Allocate a socket • Allow UDP to allocate an arbitrary local port • Specify the server • Send requests and receive replies • Close the socket
Program #4 • Using UDP to access the ECHO service • Comer, Chapter 7 (Winsock, p. 94, Linux p. 96)
#define LINELEN 128 int main(int argc, char *argv[]) { char *host ; char *service = "echo"; char buf[LINELEN+1]; int n; struct hostent *hp struct servent *sp struct protoent *pp struct sockaddr_in sin; int s; int nchars;
if (argc != 2) { fprintf(stderr, "usage: %s host\n", argv[0]); exit(1); } host = argv[1]; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
if ( sp = getservbyname(service, "udp") ) sin.sin_port = sp->s_port; else error("can't get service entry\n"); if ( hp = gethostbyname(host) ) memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) error("can't get host entry\n");
if ( (pp = getprotobyname("udp")) == 0) error("can't get protocol entry\n"); s = socket(PF_INET, SOCK_DGRAM, pp->p_proto); if (s < 0) error("can't create socket: \n"); if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) error("can't connect to host\n");