Socket Programming
Why Socket?
• How can I program a network application to?
– Share data
– Send messages
• Goal:
– How application programs use protocol software
to communicate across networks and internets
Network Layering
7 Application Application
6 Presentation Presentation
5 Session Session
4 Transport Transport
3 Network Network
2 Data link Data link
1 Physical Physical
• Transport layer and layers below
– Basic communication
– reliability
• Application Layer Functionality
– Abstractions
– Names:
• define symbolic names to identify both physical and
abstract resources available on an internet
Layering Makes it Easier
• Application programmer
– Doesn’t need to send IP packets
– Doesn’t need to send Ethernet frames
– Doesn’t need to know how TCP implements
reliability
• Only need a way to pass the data down
• Socket is the API to access transport layer
functions
What Lower Layer Need to Know?
• We pass the data down.
• What else does the lower layer need to know?
• How to identify the destination process?
– Where to send the data? (Addressing)
– What process gets the data when it is there?
(Multiplexing)
Identify the Destination
• Addressing
– IP address
– hostname (resolve to IP address via DNS)
• Multiplexing
– port
Server socket address
208.216.181.15:80
Client socket address
128.2.194.242:3479 FTP Server
(port 21)
Client HTTP Server
Connection socket pair (port 80)
(128.2.194.242:3479, 208.216.181.15:80)
Client host address Server host address
128.2.194.242 208.216.181.15
Sockets
• How to use sockets
• Important point: For 2 application programs to
communicate with each other, one application
initiates communication and the other accepts.
– Setup socket
• Where is the remote machine (IP address, hostname)
• What service gets the data (port)
– Send and Receive
• Designed just like any other I/O in Unix
• send -- write
• receive-- read
– Close the socket
Client/Server Model
How 2 application programs make contact
Server Client
•Starts first •Starts second
•Passively waits for •Actively contacts a
contact from a client server with a request
at a prearranged
•Waits for response
location
from server
•Responds to
requests
• Client-server paradigm: form of communication used
by all network applications
Overview
Client Server
socket socket
bind open_listenfd
open_clientfd
listen
Connection
connect
request accept
write read
Client /
Server
Session read write
EOF
close read
close
Socket Types
Step 1 – Setup Socket
• Both client and server need to setup the socket
– int socket(int domain, int type, int protocol);
• domain
– AF_INET -- IPv4 (AF_INET6 for IPv6)
• type
– SOCK_STREAM -- TCP
– SOCK_DGRAM -- UDP
• protocol
– the protocol (e.g. TCP or UDP)
–0
• For example,
– int sockfd = socket(AF_INET, SOCK_STREAM, 0);
Step 2 (Server) - Binding
• Only server need to bind
– int bind(int sockfd, const struct sockaddr *my_addr,
socklen_t addrlen);
• sockfd
– file descriptor socket() returned
• my_addr
– struct sockaddr_in for IPv4
– cast (struct sockaddr_in*) to (struct sockaddr*)
struct sockaddr_in {
short sin_family; // e.g. AF_INET
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_aton()
};
What is that Cast?
• bind() takes in protocol-independent (struct
sockaddr*)
struct sockaddr {
unsigned short sa_family; // address family
char sa_data[14]; // protocol address
};
– sockaddr is a generic descriptor for any kind of
socket operation,
– whereas sockaddr_in is a struct specific to IP-
based communication
– C’s polymorphism
Step 2 (Server) - Binding contd.
• addrlen
– size of the sockaddr_in
struct sockaddr_in saddr;
int sockfd;
unsigned short port = 80;
if((sockfd=socket(AF_INET, SOCK_STREAM, 0) < 0) { // from back a couple slides
printf(“Error creating socket\n”);
...
}
memset(&saddr, '\0', sizeof(saddr)); // zero structure out
saddr.sin_family = AF_INET; // match the socket() call
saddr.sin_addr.s_addr = htonl(INADDR_ANY); // bind to any local address
saddr.sin_port = htons(port); // specify port to listen on
if((bind(sockfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { // bind!
printf(“Error binding\n”);
...
}
What is htonl(), htons()?
• Byte ordering
– Network order is big-endian
– Host order can be big- or little-endian
• Conversion
– htons(), htonl(): host to network short/long
– ntohs(), ntohl(): network order to host short/long
• What need to be converted?
– Addresses
– Port
– etc.
Step 3 (Server) - Listen
• Now we can listen
– int listen(int sockfd, int backlog);
• sockfd
– again, file descriptor socket() returned
• backlog
– number of pending connections to queue
• For example,
– listen(sockfd, 5);
Step 4 (Server) - Accept
• Server must explicitly accept incoming connections
– int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
• sockfd
– again... file descriptor socket() returned
• addr
– pointer to store client address, (struct sockaddr_in *) cast to
(struct sockaddr *)
• addrlen
– pointer to store the returned size of addr, should be
sizeof(*addr)
• For example
– int isock=accept(sockfd, (struct sockaddr_in *) &caddr, &clen);
Put Server Together
struct sockaddr_in saddr, caddr;
int sockfd, clen, isock;
unsigned short port = 80;
if((sockfd=socket(AF_INET, SOCK_STREAM, 0) < 0) { // from back a couple slides
printf(“Error creating socket\n”);
...
}
memset(&saddr, '\0', sizeof(saddr)); // zero structure out
saddr.sin_family = AF_INET; // match the socket() call
saddr.sin_addr.s_addr = htonl(INADDR_ANY); // bind to any local address
saddr.sin_port = htons(port); // specify port to listen on
if((bind(sockfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { // bind!
printf(“Error binding\n”);
...
}
if(listen(sockfd, 5) < 0) { // listen for incoming connections
printf(“Error listening\n”);
...
}
clen=sizeof(caddr)
if((isock=accept(sockfd, (struct sockaddr *) &caddr, &clen)) < 0) { // accept one
printf(“Error accepting\n”);
...
}
What about client?
• Client need not bind, listen, and accept
• All client need to do is to connect
– int connect(int sockfd, const struct sockaddr
*saddr, socklen_t addrlen);
• For example,
– connect(sockfd, (struct sockaddr *) &saddr,
sizeof(saddr));
Domain Name System (DNS)
• What if I want to send data to “www.slashdot.org”?
– DNS: Conceptually, DNS is a database collection of host entries
struct hostent {
char *h_name; // official hostname
char **h_aliases; // vector of alternative hostnames
int h_addrtype; // address type, e.g. AF_INET
int h_length; // length of address in bytes, e.g. 4 for IPv4
char **h_addr_list; // vector of addresses
char *h_addr; // first host address, synonym for h_addr_list[0]
};
• hostname -> IP address
– struct hostent *gethostbyname(const char *name);
• IP address -> hostname
– struct hostent *gethostbyaddr(const char *addr, int len, int type);
Put Client Together
struct sockaddr_in saddr;
struct hostent *h;
int sockfd, connfd;
unsigned short port = 80;
if((sockfd=socket(AF_INET, SOCK_STREAM, 0) < 0) { // from back a couple slides
printf(“Error creating socket\n”);
...
}
if((h=gethostbyname(“www.slashdot.org”)) == NULL) { // Lookup the hostname
printf(“Unknown host\n”);
...
}
memset(&saddr, '\0', sizeof(saddr)); // zero structure out
saddr.sin_family = AF_INET; // match the socket() call
memcpy((char *) &saddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length); // copy the address
saddr.sin_port = htons(port); // specify port to connect to
if((connfd=connect(sockfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { // connect!
printf(“Cannot connect\n”);
...
}
We Are Connected
• Server accepting connections and client
connecting to servers
• Send and receive data
– ssize_t read(int fd, void *buf, size_t len);
– ssize_t write(int fd, const void *buf, size_t len);
• For example,
– read(sockfd, buffer, sizeof(buffer));
– write(sockfd, “hey\n”, strlen(“hey\n”));
Revisited
Client Server
socket socket
bind open_listenfd
open_clientfd
listen
Connection
connect
request accept
write read
Client /
Server
Session read write
EOF
close read
close
Close the Socket
• Don’t forget to close the socket descriptor, like
a file
– int close(int sockfd);
• Now server can loop around and accept a new
connection when the old one finishes
• What’s wrong here?
Summary
• Sockets
– socket setup
– I/O
– close
• Client: socket()----------------------->connect()->I/O->close()
• Server: socket()->bind()->listen()->accept()--->I/O->close()
• DNS
– gethostbyname()