proj1

advertisement
Introduction to Socket Programming
April 2010
What is a socket?
• An interface between application and network
– The application creates a socket
– The socket type dictates the style of
communication
• connection-oriented vs. connectionless
• Once configured, the application can
– pass data to the socket for network transmission
– receive data from the socket (transmitted through
the network by some other host)
Two essential types of sockets
• SOCK_STREAM
– TCP sockets
– reliable delivery
– in-order guaranteed
– connection-oriented
We’ll look
at this one
App
3 2
1
• SOCK_DGRAM
– UDP sockets
– unreliable delivery
– no order guarantees
– no notion of “connection”
D1
App
socket
Dest.
3 2
1
D2
socket
D3
Client – high level view
Create a socket
Setup the server address
Connect to the server
Read/write data
Shutdown connection
Some utility functions
• Byte Ordering:
Host Byte Order to Network Byte Order:
htons() , htonl()
Network Byte Order to Host Byte Order:
ntohs() , ntohl()
• IP Address format:
Ascii dotted to Binary: inet_aton()
Binary to Ascii dotted: inet_ntoa()
• Many others exist …… explore the man pages :D
Socket() – A Connection Endpoint
• This creates an endpoint for a network connection.
int socket(int domain, int type, int protocol)
domain = PF_INET (IPv4 communication)
type = SOCK_STREAM (TCP) , SOCK_DGRAM
(UDP)
protocol = 0 (for our discussion)
• Example : socket(PF_INET, SOCK_STREAM, 0);
This will create a TCP socket.
• The call returns a socket descriptor on success and 1 on an error.
int connect_ socket(char *hostname, int port) {
int sock;
Ipv4 socket address structure
struct
socketaddr_in{
struct sockaddr_in sin;
Hostent
structure
uint8_t
struct hostent{ sin_len; /*length of the structure (16)*/
struct hostent *host;
sa_falimily_t
sin_family /*/*official
AF_INT*/
charSTREAM,
* h_name
name of host*/
sock = socket(AF_ INET, SOCK_
0);
in_port_t
sin_port /*/*16
bit TCP
UDPof\
port number*/
char ** h_aliases;
pointer
ot or
array
if (sock == -1)
struct in_addr sin_addr /* 32
bit
Ipv4
address
*/
pointers to alias name*/
char
sin_zero(8)/*
unused*/
return sock;
int
h_addrtype
/* host
address type*/
} int
h_length
/* length
of address */
family , int type,
int protocol);
host = gethostbyname(hostname);Socket(int
char
** h_addr_list
/*prt
array
of ptrs
return
nonnegative value
fortoOK,
-1 for
errorwith \
if (host == NULL) {
IPv4 or IPv6 address*/
close( sock);
}
return -1;
struct
hostent
*gethostbyname(
const char *hostname);
unit16_t
htons(unit16_t
host16bitvaule)
}
/*Return
nonnull
pointer
if
OK,
NULL
error
*/ to
/*Change the port number from host on
byte
order
memset (& sin, 0, sizeof( sin));
network byte order */
connect(int socketfd, const struct sockaddr * servaddr,
sin. sin_ family = AF_ INET;
socket_t addrlen)
/*Perform the TCP three way handshaking*/
sin. sin_ port = htons(port);
sin. sin_ addr.s_ addr = *(unsigned long *) host -> h_ addr_ list[0];
if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
close (sock);
return -1;
}
return sock;
}
Make the socket
Resolve the host
Setup the struct
Connect
Server – high level view
Create a socket
Bind the socket
Listen for connections
Accept new client connections
Read/write to client connections
Shutdown connection
Bind() – Attaching to an IP and Port
• A server process calls bind to attach itself to a specific port and IP
address.
int Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
sockfd = socket descriptor returned by socket()
my_addr = pointer to a valid sockaddr_in structure cast as a
sockaddr * pointer
addrlen = length of the sockaddr_in structure
• Example :
struct sockaddr_in my;
my.sin_family = PF_INET;
my.sin_port = htons(80);
my.sin_addr.s_addr = INADDR_ANY;
bzero(&my, 8)
bind(sock, (struct sockaddr *)&my, sizeof(my));
Listen() – Wait for a connection
• The server process calls listen to tell the kernel to
initialize a wait queue of connections for this socket.
Int Listen(int sock, int backlog)
sock = socket returned by socket()
backlog = Maximum length of the pending connections
queue
• Listen() returns -1 on error (otherwise 0).
• Example: Listen(sock, 10);
This will allow a maximum of 10 connections to be in
pending state.
Listening on a port (TCP)
int make_ listen_ socket( int port) {
struct sockaddr_ in sin;
int sock;
sock = socket( AF_ INET, SOCK_ STREAM, 0);
if (sock < 0)
Make the socket
return -1;
memset(& sin, 0, sizeof( sin));
sin. sin_ family = AF_ INET;
Setup up the struct
sin. sin_ addr. s_ addr = htonl( INADDR_ ANY);
sin. sin_ port = htons( port);
if (bind( sock, (struct sockaddr *) &sin, sizeof( sin)) < 0)
Bind
return -1;
if(listen(sock,10) <bind(int
0) sockfd, const struct sockaddr * myaddr, socklen_t addrlen);
return -1; /* return 0 if OK, -1 on error
assigns a local protocol adress to a socket*/
return sock;
}
Accept() – A new connection !
• Accept is called by a Server process to accept new connections
from new clients trying to connect to the server.
Int Accept(int socket, (struct sockaddr *)&client, socklen_t *client_len)
socket = the socket in listen state
client = will hold the new client’s information
client_len = pointer to size of the client structure
• Example :
struct sockaddr_in client;
int len = sizeof(client);
Accept(sock, (struct sockaddr *)&client, &len);
Accept() return value
accept() returns a new socket descriptor
(small positive integer) or -1 on error.
After accept returns a new socket descriptor,
I/O can be done using the read() and
write() system calls.
read() and write() operate a little differently
on sockets (vs. file operation)!
Send / Recv – Finally Data !!
• Send(), Recv() , Read() , Write() etc calls are used to send and
receive data .
Int send(int sock, void *mesg, size_t len, int flags)
Int recv(int sock, void *mesg, size_t len, int flags)
sock = A connected socket
mesg = Pointer to a buffer to send/receive data from/in .
len = Size of the message buffer
flags = 0 (for our purpose)
The return value is the number of bytes actually sent/received.
• Example:
char send_buffer[1024];
char recv_buffer[1024];
int sent_bytes;
int recvd_bytes;
sent_bytes = send(sock, send_buffer, 1024, 0);
recvd_bytes = recv(sock, recv_buffer, 1024, 0);
socket()
bind()
TCP Client
Socket()
connect() Connection establishment
write()
TCP Server
Well-known port
listen()
accept()
blocks until connection from client
read()
process request
read()
close()
write()
read()
close()
Dealing with blocking calls
• Many functions block
– accept(), connect(), recv()
• For simple programs this is fine
• What about complex connection routines
– Multiple connections
– Simultaneous sends and receives
– Simultaneously doing non-networking
processing
Dealing with blocking (cont..)
• Options
– Create multi-process or multi-threaded code
– Turn off blocking feature (fcntl() system call)
– Use the select() function
• What does select() do?
– Input: a set of file descriptors
– Output: info on the file-descriptors’ status
– Therefore, can identify sockets that are “ready for
use”: calls involving that socket will return
immediately
select function call
• int status = select(int nfds, fd_set *readfds, fd_set
*writefds, fd_set *exceptfds, struct timeval *Timeout);
– Status: # of ready objects, -1 if error
– nfds: 1 +largest file descriptor to check
– readfds: list of descriptors to check if read-ready
– writefds: list of descriptors to check if write-ready
– exceptfds: list of descriptors to check if an
exception is registered
– Timeout: time after which select returns
Four parts of first project
• 0: Get build , configure and run the minet
stack
• 1: HTTP Client
• 2: Connection-at-a-time HTTP Server
• 3: Simple select-based Multipleconnection-at-a-time server
• 4: Complex …. ( Extra Credit )
Download