Socket Programming: 15-441 Computer Networks, Spring 2008 Xi Liu
Socket Programming: 15-441 Computer Networks, Spring 2008 Xi Liu
7 Application
Application Application
Application
6 Presentation
Presentation Presentation
Presentation
5 Session
Session Session
Session
4 Transport
Transport Transport
Transport
3 Network
Network Network
Network Network
Network
2 Data
Datalink
link Data
Datalink
link Data
Datalink
link
1 Physical
Physical Physical
Physical Physical
Physical
Network Layering
• Why layering?
7 Application
Application Application
Application
6 Presentation
Presentation Presentation
Presentation
5 Session
Session Session
Session
4 Transport
Transport Transport
Transport
3 Network
Network Network
Network Network
Network
2 Data
Datalink
link Data
Datalink
link Data
Datalink
link
1 Physical
Physical Physical
Physical Physical
Physical
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?
What Lower Layer Need to Know?
• We pass the data down. What else does the
lower layer need to know?
socket socket
bind open_listenfd
open_clientfd
listen
Connection
request
connect accept
write read
Client /
Server
Session read write
EOF
close read
close
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
–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
};
– C’s polymorphism
– There are structs for IPv6, etc.
Step 2 (Server) - Binding contd.
• addrlen
– size of the sockaddr_in
struct sockaddr_in saddr;
int sockfd;
unsigned short port = 80;
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]
};
socket socket
bind open_listenfd
open_clientfd
listen
Connection
request
connect 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);
call accept
User goes ret connect
out to lunch ret accept call fgets
write
Client 1
blocks call read call read
waiting for
user to type write
in data
end read
close
close
sock = socket(...); // To give you an idea of where the new code goes
bind(...); // To again give you an idea where the new code goes
Concurrency – Step 2
• Monitor sockets with select()
– int select(int maxfd, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timespec *timeout);
• maxfd
– max file descriptor + 1
• fd_set: bit vector with FD_SETSIZE bits
– readfds: bit vector of read descriptors to monitor
– writefds: bit vector of write descriptors to monitor
– exceptfds: set to NULL
• timeout
– how long to wait without activity before returning
What about bit vectors?
• void FD_ZERO(fd_set *fdset);
– clear out all bits
• void FD_SET(int fd, fd_set *fdset);
– set one bit
• void FD_CLR(int fd, fd_set *fdset);
– clear one bit
• int FD_ISSET(int fd, fd_set *fdset);
– test whether fd bit is set
The Server
// socket() call and non-blocking code is above this point
clen=sizeof(caddr);
while(1) {
pool.ready_set = pool.read_set; // Save the current state
pool.nready = select(pool.maxfd+1, &pool.ready_set, &pool.write_set, NULL, NULL);
...
close(sockfd);
What is pool?
typedef struct { /* represents a pool of connected descriptors */
int maxfd; /* largest descriptor in read_set */
fd_set read_set; /* set of all active read descriptors */
fd_set write_set; /* set of all active read descriptors */
fd_set ready_set; /* subset of descriptors ready for reading */
int nready; /* number of ready descriptors from select */
int maxi; /* highwater index into client array */
int clientfd[FD_SETSIZE]; /* set of active descriptors */
rio_t clientrio[FD_SETSIZE]; /* set of active read buffers */
... // ADD WHAT WOULD BE HELPFUL FOR PROJECT1
} pool;
What about checking clients?
• The main loop only tests for incoming connections
– There are other reasons the server wakes up
– Clients are sending data, pending data to write to
buffer, clients closing connections, etc.
• Store all client file descriptors
– in pool
• Keep the while(1) loop thin
– Delegate to functions
• Come up with your own design
Summary
• Sockets
– socket setup
– I/O
– close
• Client: socket()----------------------->connect()->I/O->close()
• Server: socket()->bind()->listen()->accept()--->I/O->close()
• DNS
– gethostbyname()
• Concurrency
– select()
• Bit vector operations
– fd_set, FD_ZERO(), FD_SET(), FD_CLR(), FD_ISSET()
About Project 1
• Standalone IRC server
– Checkpoint 1: subversion and Makefile
• Check in a Makefile and source code
• Makefile can build executable named sircd
• No server functions necessary
– Checkpoint 2: echo server
• Use select() to handle multiple clients
Suggestions
• Start early!
– Work ahead of checkpoints
• Read the man pages
• Email (xil at cs dot cmu dot edu) if you didn’t
get a svn username and password