420 likes | 833 Views
Sockets Programming in Linux. References: Internetworking with TCP/IP Vol III - Linux version UNIX Network Programming - W. Richard Stevens. Sockets Programming in Linux. Linux / UNIX Socket API functions Example TCP / UDP Clients Example TCP / UDP Servers.
E N D
Sockets Programming in Linux References: Internetworking with TCP/IP Vol III - Linux version UNIX Network Programming - W. Richard Stevens
Sockets Programming in Linux • Linux / UNIX Socket API functions • Example TCP / UDP Clients • Example TCP / UDP Servers
Basic Socket FunctionsServer(Linux / UNIX) • Create a socket of a particular type • retcode = socket (family, type, protocol ) • s = socket (PF_INET, SOCK_STREAM, 0); • returns socket number or -1 on error • Bind that socket to a specific port • retcode = bind (socket, localaddr, addrlen ) • n = bind (s, (struct sockaddr *)myaddr, sizeof(myaddr)); • returns 0 on success, -1 on fail
Basic Socket FunctionsServer(Linux / UNIX) • Wait for an incoming message • retcode = listen (socket, queuelen) • ans = listen(s, 0); /* queuelen max ~ 5*/ • return value 0 = success, -1 = fail • Create a new socket and return new socket ID to client • retcode = accept (socket, addr, addrlen) • ans = accept (s, (struct sockaddr *)cl_addr, sizeof(cl_addr)); • return value socket number = success, -1 = fail
Basic Socket Functions Server (Linux / UNIX) • Read / send a message • retcode = read [write] (socket, buff, bufflen) • ans = read (s, buf, sizeof(buf)); • ans = write (s, buf, strlen(buf)); • return value word count = success, -1 = fail • retcode = recv [send] (socket, buff, bufflen, 0) • ans = recv (s, buf, sizeof(buf), 0); • ans = send (s, buf, strlen(buf), 0); • return value word count = success, -1 = fail • Close the socket • retcode = shutdown (socket , direction) • direction: 0 means input, 1 means output, 2 means both • retcode = close (socket ); • return value 0 = success, -1 = fail
Basic Socket FunctionsClient (Linux / UNIX) • Create a socket of a particular type • Socket ( ) • Establish a connection to a remote Port/Socket • retcode = connect (socket, addr, addrlen) • ans = connect (s, (struct sockaddr *)&svr, sizeof(svr)) • return value 0 = success, -1 = fail • Send and receive messages to/from remote socket • Read( ) / Write( ) of recv( ) / send( • Close the socket • Close ( )
Additional Socket Functions(Linux / UNIX) • Byte ordering functions • servaddr.sin_port = htons (SERV_PORT) • myaddr.sin_addr.s_addr = htonl (INADDR_ANY) • Name resolution functions • host / protocol / service, by name / address / port • Other Stuff • zero out memory blocks • bzero ((char *)&myaddr, sizeof(myaddr)); • copy memory blocks • bcopy (hp->h_addr, (caddr_T)&svaddr.sin_addr, hp->h_length)
Example Linux Client • Develop a set of procedures that can be used by other programs to implement client / server. int connectTCP (host, service) int connectsock(host, service, “tcp”) [identify service, host, port] [get a socket] [connect to service / host / port] [return socket number]
Linux Client - Connectsock.c int connectTCP (char *host, char *service) { return connectsock (host, service, “tcp”); }
Linux Client - Connectsock.c #include <sys/types.h>, <sys/socket.h>, <netinet/in.h>,<netdb.h> int connectsock (char *host, char *service, char *protocol) { struct hostent *phe; struct servent *pse; struct protoent *ppe; struct sockaddr_in sin; int s, type;
Linux Client - Connectsock.c bzero ((char *)&sin, sizeof (sin)); sin.sin_family = AF_INET; if (pse = getservbyname (service, protocol) ) sin.sin_port = pse ->s_port; else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0) error_exit (“can’t get %s service\n”, service); if (phe = gethostbyname (host) ) bcopy(phe->h_addr, (char *)&sin.sin_addr, phe->h_length); else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) error_exit (“can’t get %s host\n”, host);
Linux Client - Connectsock.c if ( (ppe = getprotobyname (protocol) == 0) error_exit (“can’t get %s host\n”, host); if (strcmp (protocol, “tcp”) == 0) type = SOCK_STREAM; else type = SOCK_DGRAM; if (s = socket (PF_INET, type, ppe->p_proto)) < 0) error_exit (“Can’t create a socket\n”); if (connect (s, (struct sockaddr *)&sin, sizeof(sin)) < 0) error_exit (“can’t connect to remote socket\n”); return s; }
Example Linux Client - TCPecho.c #include <stdio.h> #define LINELEN 128 int main (argc, argv) { host = argv[1]; service = argv[2]; TCPecho (host, service); exit (0); }
Example Linux Client - TCPecho.c int TCPecho (char *host, char *service) { char buf[LINELEN+1]; int s, n, outchars, inchars; s = connectTCP (host, service); while (fgets (buf, sizeof(buf), stdin)) { buf[LINELEN] = ‘\0’; outchars = strlen(buf); (void) write (s, buf, outchars);
Example Linux Client - TCPecho.c for (inchars = 0; inchars < outchars; inchars +=n) { n = read (s, &buf[inchars], outchars - inchars); if (n < 0) error_exit(“socket read failed\n”); } fputs (buf, stdout); } }
TCP Client Algorithm Issues • Client / Server Communications • request / response interaction • write / read (send / recv) • Single write may require multiple reads • response may be segmented • continue appending reads until return length = 0
Example Linux Client - UDPecho.c #include <stdio.h> #define LINELEN 128 int main (argc, argv) { host = argv[1]; service = argv[2]; UDPecho (host, service); exit (0); }
Example Linux Client - UDPecho.c int UDPecho (char *host, char *service) { char buf[LINELEN+1]; int s, n, outchars, inchars; s = connectUDP (host, service); while (fgets (buf, sizeof(buf), stdin)) { buf[LINELEN] = ‘\0’; outchars = strlen(buf); (void) write (s, buf, outchars);
Example Linux Client - UDPecho.c if (read (s, buf, nchars) < 0) error_exit (“Socket read failed \n”); fputs (buf, stdout); } }
Iterative Connectionless ServerTIME Server /* UDPtimed.c - main */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <time.h> #include <string.h> extern int errno; int passiveUDP(const char *service); int errexit(const char *format, ...); #define UNIXEPOCH 2208988800 /* UNIX epoch, in secs*/
Iterative Connectionless ServerTIME Server int main(int argc, char *argv[]) { struct sockaddr_in fsin; /* the address of a client */ char * service = "time"; /* service name or port number */ char buf[1]; /* "input" buffer; any size > 0 */ int sock; /* server socket */ time_t now; /* current time */ int alen; /* from-address length */ switch (argc) { case 1: break; case 2: service = argv[1]; break; default: errexit("usage: UDPtimed [port]\n"); }
Iterative Connectionless ServerTIME Server sock = passiveUDP(service); while (1) { alen = sizeof(fsin); if (recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&fsin, &alen) < 0) errexit("recvfrom: %s\n", strerror(errno)); (void) time(&now); now = htonl((u_long)(now + UNIXEPOCH)); (void) sendto(sock, (char *)&now, sizeof(now), 0, (struct sockaddr *)&fsin, sizeof(fsin)); } }
Concurrent Connection-OrientedTCPechod.c #include <sys/types.h, <sys/signal.h, <sys/socket.h, <sys/time.h, <sys/resource.h, <sys/wait.h, <sys/errno.h, <netinet/in.h>, <pthread.h>, <unistd.h>, <stdlib.h>, <stdio.h>, <string.h>, <errno.h> #define QLEN 10 /* max connect queue length*/ #define BUFSIZE 4096 extern int errno; void * TCPechod(void *pfd); int errexit(const char *format, ...); int passiveTCP(const char *service, int qlen);
Concurrent Connection-OrientedTCPechod.c int main(int argc, char *argv[]) { char *service = "echo"; /* service name/port #*/ struct sockaddr_in fsin; /* address of client*/ unsigned int alen; /* len of client addr*/ int msock; /* master server socket */ int ssock; /* slave server socket */ pthread_t tid; switch (argc) { case 1: break; case 2: service = argv[1]; break; default: errexit("usage: TCPechod [port]\n"); }
Concurrent Connection-OrientedTCPechod.c msock = passiveTCP(service, QLEN); while (1) { alen = sizeof(fsin); ssock = accept (msock, (struct sockaddr *)&fsin, &alen); if (ssock < 0) { errexit("accept: %s\n", strerror(errno)); } //Now create a thread to handle client request pthread_create (&tid, NULL, &TCPechod, (void *)&ssock); } //end of while }//end of main
Concurrent Connection-OrientedTCPechod.c msock = passiveTCP(service, QLEN); while (1) { alen = sizeof(fsin); ssock = accept(msock, (struct sockaddr *)&fsin, &alen); if (ssock < 0) { errexit("accept: %s\n", strerror(errno)); } //Now create a thread to handle client request pthread_create (&tid, NULL, &TCPechod, (void *)&ssock); } //end of while }//end of main
Concurrent Connection-OrientedTCPechod.c void * TCPechod(void * pfd) { char buf[BUFSIZE]; int cc, fd; fd = * (int *) pfd; while (cc = recv(fd, buf, sizeof (buf), 0)) { if (cc < 0) errexit("echo read: %s\n", strerror(errno)); printf ("We got: %s\n", buf); if (send(fd, buf, cc, 0) < 0) errexit("echo write: %s\n", strerror(errno)); bzero (&buf, sizeof(buf)); } }
Summary • Sockets API almost identical in Windows and Linux • Linux does not use WSAStartup, WSACleanup • Linux uses close(socket), Windows uses closesocket() • Some differences in Operating System functions • Multiple threads • Windows - _beginthread (…) • Linux – pthread_create (…) • Multiple Processes • Windows – CreateProcess(…) • Linux – Fork()