Socket Programming r What is a socket r

  • Slides: 39
Download presentation
Socket Programming r What is a socket? r Using sockets m Types (Protocols) m

Socket Programming r What is a socket? r Using sockets m Types (Protocols) m Associated functions m Styles m We will look at using sockets in C 1

What is a socket? r An interface between application and network m The application

What is a socket? r An interface between application and network m The application creates a socket m The socket type dictates the style of communication • reliable vs. best effort • connection-oriented vs. connectionless r Once configured the application can m pass data to the socket for network transmission m receive data from the socket (transmitted through the network by some other host) 2

Two essential types of sockets r SOCK_STREAM m m m r SOCK_DGRAM a. k.

Two essential types of sockets r SOCK_STREAM m m m r SOCK_DGRAM a. k. a. TCP reliable delivery in-order guaranteed connection-oriented bidirectional m m m App 3 2 1 socket Dest. a. k. a. UDP unreliable delivery no order guarantees no notion of “connection” – app indicates dest. for each packet can send or receive D 1 App 3 2 1 D 2 socket Q: why have type SOCK_DGRAM? D 3 3

Socket Creation in C: socket r int s = socket(domain, type, protocol); m s:

Socket Creation in C: socket r int s = socket(domain, type, protocol); m s: socket descriptor, an integer (like a file-handle) m domain: integer, communication domain • e. g. , PF_INET (IPv 4 protocol) – typically used m type: communication type • SOCK_STREAM: reliable, 2 -way, connection-based service • SOCK_DGRAM: unreliable, connectionless, • other values: need root permission, rarely used, or obsolete specifies protocol (see file /etc/protocols for a list of options) - usually set to 0 r NOTE: socket call does not specify where data will be coming from, nor where it will be going to – it just creates the interface! 4 m protocol:

A Socket-eye view of the Internet medellin. cs. columbia. edu (128. 59. 21. 14)

A Socket-eye view of the Internet medellin. cs. columbia. edu (128. 59. 21. 14) newworld. cs. umass. edu (128. 119. 245. 93) cluster. cs. columbia. edu (128. 59. 21. 14, 128. 59. 16. 7, 128. 59. 16. 5, 128. 59. 16. 4) r Each host machine has an IP address r When a packet arrives at a host 5

Ports r Each host has 65, 536 ports r Some ports are reserved for

Ports r Each host has 65, 536 ports r Some ports are reserved for specific apps Port 0 Port 1 Port 65535 m 20, 21: FTP r A socket provides an interface m 23: Telnet to send data to/from the network through a port m 80: HTTP m see RFC 1700 (about 2000 ports are reserved) 6

Addresses, Ports and Sockets r Like apartments and mailboxes m You are the application

Addresses, Ports and Sockets r Like apartments and mailboxes m You are the application m Your apartment building address is the address m Your mailbox is the port m The post-office is the network m The socket is the key that gives you access to the right mailbox (one difference: assume outgoing mail is placed by you in your mailbox) r Q: How do you choose which port a socket connects to? 7

The bind function r associates and (can exclusively) reserves a port for use by

The bind function r associates and (can exclusively) reserves a port for use by the socket r int status = bind(sockid, &addrport, size); m m status: error status, = -1 if bind failed sockid: integer, socket descriptor addrport: struct sockaddr, the (IP) address and port of the machine (address usually set to INADDR_ANY – chooses a local address) size: the size (in bytes) of the addrport structure r bind can be skipped for both types of sockets. When and why? 8

Skipping the bind r SOCK_DGRAM: m if only sending, no need to bind. The

Skipping the bind r SOCK_DGRAM: m if only sending, no need to bind. The OS finds a port each time the socket sends a pkt m if receiving, need to bind r SOCK_STREAM: m destination determined during conn. setup m don’t need to know port sending from (during connection setup, receiving end is informed of port) 9

Connection Setup (SOCK_STREAM) r Recall: no connection setup for SOCK_DGRAM r A connection occurs

Connection Setup (SOCK_STREAM) r Recall: no connection setup for SOCK_DGRAM r A connection occurs between two kinds of participants m m passive: waits for an active participant to request connection active: initiates connection request to passive side r Once connection is established, passive and active participants are “similar” m m both can send & receive data either can terminate the connection 10

Connection setup cont’d r Passive participant m step 1: listen (for incoming requests) m

Connection setup cont’d r Passive participant m step 1: listen (for incoming requests) m step 3: accept (a request) m step 4: data transfer r The accepted connection is on a new socket r The old socket continues to listen for other active participants r Why? r Active participant m m step 2: request & establish connection step 4: data transfer Passive Participant a-sock-1 l-sock a-sock-2 socket Active 1 Active 2 11

Connection setup: listen & accept r Called by passive participant r int status =

Connection setup: listen & accept r Called by passive participant r int status = listen(sock, queuelen); m status: 0 if listening, -1 if error m sock: integer, socket descriptor m queuelen: integer, # of active participants that can “wait” for a connection m listen is non-blocking: returns immediately r int s = accept(sock, &namelen); m s: integer, the new socket (used for data-transfer) m sock: integer, the orig. socket (being listened on) m name: struct sockaddr, address of the active participant m namelen: sizeof(name): value/result parameter • must be set appropriately before call • adjusted by OS upon return m accept is blocking: waits for connection before returning 12

connect call r int status = connect(sock, &name, namelen); m status: 0 if successful

connect call r int status = connect(sock, &name, namelen); m status: 0 if successful connect, -1 otherwise m sock: integer, socket to be used in connection m name: struct sockaddr: address of passive participant m namelen: integer, sizeof(name) r connect is blocking 13

Sending / Receiving Data r With a connection (SOCK_STREAM): m int count = send(sock,

Sending / Receiving Data r With a connection (SOCK_STREAM): m int count = send(sock, &buf, len, flags); • • m int • • count: # bytes transmitted (-1 if error) buf: char[], buffer to be transmitted len: integer, length of buffer (in bytes) to transmit flags: integer, special options, usually just 0 count = recv(sock, &buf, len, flags); count: # bytes received (-1 if error) buf: void[], stores received bytes len: # bytes received flags: integer, special options, usually just 0 m Calls are blocking [returns only after data is sent (to socket buf) / received] 14

Sending / Receiving Data (cont’d) r Without a connection (SOCK_DGRAM): m int count =

Sending / Receiving Data (cont’d) r Without a connection (SOCK_DGRAM): m int count = sendto(sock, &buf, len, flags, &addr, addrlen); • count, sock, buf, len, flags: same as send • addr: struct sockaddr, address of the destination • addrlen: sizeof(addr) m int count = recvfrom(sock, &buf, len, flags, &addrlen); • count, sock, buf, len, flags: same as recv • name: struct sockaddr, address of the source • namelen: sizeof(name): value/result parameter r Calls are blocking [returns only after data is sent (to socket buf) / received] 15

close r When finished using a socket, the socket should be closed: r status

close r When finished using a socket, the socket should be closed: r status = close(s); 0 if successful, -1 if error m s: the file descriptor (socket being closed) m status: r Closing a socket m closes a connection (for SOCK_STREAM) m frees up the port used by the socket 16

The struct sockaddr r The generic: struct sockaddr { u_short sa_family; char sa_data[14]; };

The struct sockaddr r The generic: struct sockaddr { u_short sa_family; char sa_data[14]; }; m sa_family • specifies which address family is being used • determines how the remaining 14 bytes are used r The Internet-specific: struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; m sin_family = AF_INET m sin_port: port # (0 -65535) m sin_addr: IP-address m sin_zero: unused 17

Address and port byte-ordering r Address and port are stored as integers m m

Address and port byte-ordering r Address and port are stored as integers m m u_short sin_port; (16 bit) in_addr sin_addr; (32 bit) struct in_addr { u_long s_addr; }; r Problem: m different machines / OS’s use different word orderings • little-endian: lower bytes first • big-endian: higher bytes first m these machines may communicate with one another over the network 128. 119. 40. 12 128 Big-Endian machine 119 40 12 Little-Endian machine N O R 119 40 W 128 ! ! ! G 12. 40. 119. 128 12 18

Solution: Network Byte-Ordering r Defs: m Host Byte-Ordering: the byte ordering used by a

Solution: Network Byte-Ordering r Defs: m Host Byte-Ordering: the byte ordering used by a host (big or little) m Network Byte-Ordering: the byte ordering used by the network – always big-endian r Any words sent through the network should be converted to Network Byte-Order prior to transmission (and back to Host Byte-Order once received) r Q: should the socket perform the conversion automatically? r Q: Given big-endian machines don’t need conversion routines and little-endian machines do, how do we avoid writing two versions of code? 19

UNIX’s byte-ordering funcs r u_long htonl(u_long x); r u_long ntohl(u_long x); r u_short htons(u_short

UNIX’s byte-ordering funcs r u_long htonl(u_long x); r u_long ntohl(u_long x); r u_short htons(u_short x); r u_short ntohs(u_short x); r On big-endian machines, these routines do nothing r On little-endian machines, they reverse the byte order hto 128 119 40 12 Little-Endian 12 machine 128 119 40 40 119 128. 119. 40. 12 12 ntohl nl 128 119 40 128. 119. 40. 12 Big-Endian 12 machine r Same code would have worked regardless of endian- ness of the two machines 20

Dealing with blocking calls r Many of the functions we saw block until a

Dealing with blocking calls r Many of the functions we saw block until a certain event m m accept: until a connection comes in connect: until the connection is established recv, recvfrom: until a packet (of data) is received send, sendto: until data is pushed into socket’s buffer • Q: why not until received? r For simple programs, blocking is convenient r What about more complex programs? m multiple connections m simultaneous sends and receives m simultaneously doing non-networking processing 21

Dealing w/ blocking (cont’d) r Options: m create multi-process or multi-threaded code m turn

Dealing w/ blocking (cont’d) r Options: m create multi-process or multi-threaded code m turn off the blocking feature (e. g. , using the fcntl filedescriptor control function) m use the select function call. r What does select do? m can be permanent blocking, time-limited blocking or nonblocking m input: a set of file-descriptors m output: info on the file-descriptors’ status m i. e. , can identify sockets that are “ready for use”: calls involving that socket will return immediately 22

Other useful functions r bzero(char* c, int n): 0’s n bytes starting at c

Other useful functions r bzero(char* c, int n): 0’s n bytes starting at c r gethostname(char *name, int len): gets the name of the current host r gethostbyaddr(char *addr, int len, int type): converts IP hostname to structure containing long integer r inet_addr(const char *cp): converts dotted-decimal char-string to long integer r inet_ntoa(const struct in_addr in): converts long to dotted-decimal notation r Warning: check function assumptions about byte- ordering (host or network). Often, they assume parameters / return solutions in network byteorder 23

Release of ports r Sometimes, a “rough” exit from a program (e. g. ,

Release of ports r Sometimes, a “rough” exit from a program (e. g. , ctrl -c) does not properly free up a port r Eventually (after a few minutes), the port will be freed r To reduce the likelihood of this problem, include the following code: #include <signal. h> void clean. Exit(){exit(0); } m in socket code: signal(SIGTERM, clean. Exit); signal(SIGINT, clean. Exit); 24

Example – Daytime Server/Client Daytime client Application protocol Socket API TCP IP MAC driver

Example – Daytime Server/Client Daytime client Application protocol Socket API TCP IP MAC driver Daytime server TCP protocol IP protocol MAC-level protocol Actual data flow Network TCP IP MAC driver MAC = media access control 25

TCP Daytime client r Connects to a daytime server r Retrieves the current date

TCP Daytime client r Connects to a daytime server r Retrieves the current date and time % gettime 130. 245. 1. 44 Thu Sept 05 15: 50: 00 2002 26

#include "unp. h" int main(int argc, char **argv) { int sockfd, n; char recvline[MAXLINE

#include "unp. h" int main(int argc, char **argv) { int sockfd, n; char recvline[MAXLINE + 1]; struct sockaddr_in servaddr; if( argc != 2 )err_quit(“usage : gettime <IP address>”); /* Create a TCP socket */ if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) err_sys("socket error"); /* Specify server’s IP address and port */ bzero(&servaddr, sizeof(servaddr)); servaddr. sin_family = AF_INET; servaddr. sin_port = htons(13); /* daytime server port */ if (inet_pton(AF_INET, argv[1], &servaddr. sin_addr) <= 0) err_quit("inet_pton error for %s", argv[1]); 27

/* Connect to the server */ if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)

/* Connect to the server */ if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) err_sys("connect error"); /* Read the date/time from socket */ while ( (n = read(sockfd, recvline, MAXLINE)) > 0) { recvline[n] = 0; /* null terminate */ printf(“%s”, recvline); } if (n < 0) err_sys("read error"); close(sockfd); } 28

Simplifying error-handling int Socket(int family, int type, int protocol) { int n; if (

Simplifying error-handling int Socket(int family, int type, int protocol) { int n; if ( (n = socket(family, type, protocol)) < 0) err_sys("socket error"); return n; } 29

TCP Daytime Server r Waits for requests from Client r Accepts client connections r

TCP Daytime Server r Waits for requests from Client r Accepts client connections r Send the current time r Terminates connection and goes back waiting for more connections. 30

#include "unp. h" <time. h> int main(int argc, char **argv) { int listenfd, connfd;

#include "unp. h" <time. h> int main(int argc, char **argv) { int listenfd, connfd; struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; /* Create a TCP socket */ listenfd = Socket(AF_INET, SOCK_STREAM, 0); /* Initialize server’s address and well-known port */ bzero(&servaddr, sizeof(servaddr)); servaddr. sin_family = AF_INET; servaddr. sin_addr. s_addr = htonl(INADDR_ANY); servaddr. sin_port = htons(13); /* daytime server */ /* Bind server’s address and port to the socket */ Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 31

/* Convert socket to a listening socket */ Listen(listenfd, LISTENQ); for ( ; ;

/* Convert socket to a listening socket */ Listen(listenfd, LISTENQ); for ( ; ; ) { /* Wait for client connections and accept them */ connfd = Accept(listenfd, (SA *) NULL, NULL); /* Retrieve system time */ ticks = time(NULL); snprintf(buff, sizeof(buff), "%. 24 srn", ctime(&ticks)); /* Write to socket */ Write(connfd, buff, strlen(buff)); /* Close the connection */ Close(connfd); } } 32

The Socket Structure INET Address struct in_addr { in_addr_t s_addr; } /* 32 -bit

The Socket Structure INET Address struct in_addr { in_addr_t s_addr; } /* 32 -bit IPv 4 address */ INET Socket Struct sockaddr_in { uint 8_t sin_len; /* length of structure (16) */ sa_family_t sin_family; /* AF_INET */ in_port_t sin_port; /* 16 -bit TCP/UDP port number */ struct in_addr sin_addr; /* 32 -bit IPv 4 address */ char sin_zero[8]; /* unused */ } 33

UDP Client Code r #include <stdio. h> r #include <sys/types. h> r #include <sys/socket.

UDP Client Code r #include <stdio. h> r #include <sys/types. h> r #include <sys/socket. h> r #include <netinet/in. h> r #include <arpa/inet. h> r #include <errno. h> r #define MY_PORT_ID r r r 6089 #define SERVER_PORT_ID 6090 #define SERV_HOST_ADDR "128. 119. 40. 186" main(){ int sockid, retcode; struct sockaddr_in my_addr, server_addr; char msg[12]; 34

UDP Client (cont. ) r printf("Client: creating socketn"); r r r if ( (sockid

UDP Client (cont. ) r printf("Client: creating socketn"); r r r if ( (sockid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { printf("Client: socket failed: %dn", errno); exit(0); } printf("Client: binding my local socketn"); bzero((char *) &my_addr, sizeof(my_addr)); my_addr. sin_family = AF_INET; my_addr. sin_addr. s_addr = htonl(INADDR_ANY); my_addr. sin_port = htons(MY_PORT_ID); if ( (bind(sockid, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) ) { printf("Client: bind fail: %dn", errno); exit(0); } 35

UDP Client (fin) r printf("Client: creating addr structure for servern"); r bzero((char *) &server_addr,

UDP Client (fin) r printf("Client: creating addr structure for servern"); r bzero((char *) &server_addr, sizeof(server_addr)); r r r r server_addr. sin_family = AF_INET; server_addr. sin_addr. s_addr = inet_addr(SERV_HOST_ADDR); server_addr. sin_port = htons(SERVER_PORT_ID); printf("Client: initializing message and sendingn"); sprintf(msg, "Hello world"); retcode = sendto(sockid, msg, 12, 0, (struct sockaddr *) &server_addr, sizeof(server_addr)); if (retcode <= -1) {printf("client: sendto failed: %dn", errno); exit(0); } /* close socket */ close(sockid); } 36

UDP Server r #include <stdio. h> r #include <sys/types. h> r #include <sys/socket. h>

UDP Server r #include <stdio. h> r #include <sys/types. h> r #include <sys/socket. h> r #include <netinet/in. h> r #include <arpa/inet. h> r #include <errno. h> r #define MY_PORT_ID 6090 /* a number > 5000 */ r main(){ r int sockid, nread, addrlen; struct sockaddr_in my_addr, client_addr; r char msg[50]; r 37

UDP Server (cont) r printf("Server: creating socketn"); r r r r if ( (sockid

UDP Server (cont) r printf("Server: creating socketn"); r r r r if ( (sockid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { printf("Server: socket error: %dn", errno); exit(0); } printf("Server: binding my local socketn"); bzero((char *) &my_addr, sizeof(my_addr)); my_addr. sin_family = AF_INET; my_addr. sin_addr. s_addr = htons(INADDR_ANY); my_addr. sin_port = htons(MY_PORT_ID); if ( (bind(sockid, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) ) { printf("Server: bind fail: %dn", errno); exit(0); } 38

UDP Server (end) r printf("Server: starting blocking message readn"); r nread = recvfrom(sockid, msg,

UDP Server (end) r printf("Server: starting blocking message readn"); r nread = recvfrom(sockid, msg, 11, 0, (struct sockaddr *) &client_addr, &addrlen); r printf("Server: return code from read is %dn", nread); r if (nread >0) printf("Server: message is: %sn", msg); r close(sockid); r } 39