Sockets - Classes

Download Report

Transcript Sockets - Classes

Server Sockets:
Web Server
Server Socket/Port
Client 1
Client 2
Client 3
Client n
• A server socket listens on a given port
• Many different clients may be connecting to that
port
• Ideally, you would like a separate file descriptor
for each client connection
Server Sockets:
Web Server
New socket
2: Server creates new file
descriptor for client which
is used for bi-directional
communication. All future
communication with
client is done with this
new file descriptor.
Client 1
Server Socket/Port
1: Client requests
connection
3: Other clients requesting
connections can now be
serviced.
Client 2
Server Sockets
• How to use the socket API to listen for an accept
connections
• Start by describing a non-concurrent implementation of a
server (only one thread of execution)
The code I provided for project 5 is a non-concurrent
implementation. You will modify it to make it concurrent.
• Procedure
–
–
–
–
–
Create network endpoint with socket()
Bind socket to a port - bind()
Start listening for connections - listen()
Loop and accept connections - accept()
Read and write data to client - send(), recv(), read(), write()
Creating the Socket
Socket() creates an endpoint for network communication
int socket(int domain, int type, int protocol);
For IP (Internet Protocol), use
AF_INET.
For communication within a
single machine, use AF_UNIX
Returns file
descriptor
or -1
For TCP, use SOCK_STREAM
For UDP, use SOCK_DGRAM
This argument is for
making a selection if the
type (the previous
argument) offers a
choice. 0 is the default
and should be used in
most cases.
if ((sockfd = socket(AF_INET,SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
Internet Protocol
The Internet protocol family is comprised of
the Internet Protocol ("IP"), the Address
Resolution Protocol ("ARP"), the Internet
Control Message Protocol ("ICMP"), the
Transmission Control Protocol ("TCP"), and
the User Datagram Protocol ("UDP").
Bind the Socket to a Port
• Ports allow multiple network processes on a
machine with a single address.
• A server has to choose a port where clients can
contact it.
• It is important that standard services be at the
same port on all computers so that clients will
know their addresses. The FTP port is 21. The
usual port for a web server is 80. Port numbers
above 2000 are generally available.
• bind() associates the chosen port with a socket
already created with the socket() command.
Binding the socket
bind() connects a server socket to a port
int bind(int sockfd, struct sockaddr *address,
size_t add_len);
0 on success
or -1 on error
Network address structure
identifying port to listen on.
See next slide.
The int returned from socket call.
Size of address structure
if (bind(sockfd, (struct sockaddr *) &server, sizeof(server)) == -1) {
perror("bind call failed");
exit(1);
}
nd
2 Argument
of bind
• even though bind() wants a struct
sockaddr*, you can still use a struct
sockaddr_in and cast it to be a sockaddr *
Setting up an address
The sockaddr_in structure is used to set up an
internet address.
This structure is defined in <netinet/in.h>.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(7000);
server.sin_addr.s_addr = INADDR_ANY;
server.sin_zero[8] /* not used */
Argument 1 of sockaddr_in
sin_family
• We want communication across different
machines so we will not use AF_UNIX.
• We will use AF_INET.
• This should be the same as you used in the
first argument of the socket call.
Argument 2 of sockaddr_in
sin_port
• The second field of serv_addr_in is unsigned short
sin_port , which contain the port number.
However, instead of simply copying the port
number to this field, it is necessary to convert this
to network byte order using the function htons()
which converts a port number in host byte order to
a port number in network byte order.
• Different machines store numbers differently
internally. Some are big endian, some are little
endian. htons lets computers with different
schemes communicate. See next slide.
Big endian and Little endian
computers
• Virtually all computer architectures are byte
addressable. If an int is four bytes, there are two
different ways to store this. Suppose the address of
the int is A. In a so-called big endian computer, the
highest order byte is stored at A, and the lowest
order byte is stored at address A+3. In a so-called
little endian computer, address A stores the least
significant byte and the most significant byte is at
address A+3.
Argument 3 of sockaddr_in
sin_addr
• The sin_addr field of the sockaddr_in structure
specifies a local or remote IP address. Each
network interface has its own unique IP address.
The special value INADDR_ANY may be used in
this field to effect "wildcard" matching. Given in a
bind() call, this value leaves the local IP address of
the socket unspecified, so that the socket will
receive connections or messages directed at any of
the valid IP addresses of the system.
Argument 4 of sockaddr_in
sin_zero[8]
• sin_zero (which is included to pad the
structure to the length of a struct sockaddr)
should be set to all zeros with the function
memset().
Listening for Connections
• The server will ignore any connection
attempts until you tell the socket() to start
listening
• This is done with listen()
Listen
listen() causes the socket to start listening for connections
int listen(int sockfd, int queue_size);
Maximum numbers of
connections to queue up
0 on success
or -1 on error
if (listen(sockfd, 5) == -1) {
perror("listen call failed");
exit(1);
}
listen()
• The first argument is the socket file
descriptor, and the second is the size of the
backlog queue, i.e., the number of
connections that can be waiting while the
process is handling a particular connection.
This should be set to 5, the maximum size
permitted by most systems. If the first
argument is a valid socket, this call cannot
fail.
Loop and Accept
• Servers generally run continually, waiting
for clients to contact them.
• Thus a server has an "infinite loop" that
continually processes connections from
clients.
• The accept() function takes the next
connection off the listen queue or blocks the
process until a connection arrives.
Project 5
• The code I supplied with project 5 does not
have this infinite loop. You will modify the
code I gave you to put accept() in this loop.
accept() blocks until a client connects.
Every time a client connects, you should
fork off a child and let the child handle the
communication with the client. Meanwhile
the parent will go back to accept more client
connections.
Accept Returns a New File Descriptor
• Your child will communicate with the client using
the new file descriptor NOT the file descriptor
returned by socket.
• Your parent will close its copy of the new file
descriptor because it will not be involved with
further communication with the client after the
connection is made. Don’t forget to implement
signal handling for SIGCHLD. You MUST wait
for these children when they finish.
Accept
accept() returns the next client connection
int accept(int sockfd, struct sockaddr *address,
size_t &add_len);
Returns file
descriptor
or -1
Network address structure
identifying client. This can
be NULL pointer
Pointer to variable containing size
of address structure, can be NULL
while (1) {
client_sockfd = accept(sockfd, NULL, NULL);
if (client_sockfd == -1) {
perror("accept call failed");
/* Here you may want to continue or exit - depends */
}
}