Sockets CIS 370 Lab 10 UMass Dartmouth. Introduction 4 Sockets provide a simple programming...
-
Upload
eric-mcdonald -
Category
Documents
-
view
216 -
download
0
Transcript of Sockets CIS 370 Lab 10 UMass Dartmouth. Introduction 4 Sockets provide a simple programming...
Sockets
CIS 370
Lab 10
UMass Dartmouth
Introduction
Sockets provide a simple programming interface which is consistent for processes on the same machine or across different machines.
The aim of UNIX sockets is to provide a means of IPC that is sufficiently generic to allow bi-directional messages between two processes irrespective of where they reside.
General Information For any communication to take place between
processes, the machines on which they are running must be connected.– Hardware level: network equipment such as cables,
cards and devices such as routers. – Software level: by a standard set of network protocols.
Simplest IPC model is client-server.– Server is a process which provides a service.– Client is a process (possibly on another host) that
connects to the server to invoke its service.
Types of Communication
Processes that send messages across a network can choose one of two ways to communicate.– The connection-oriented model (virtual circuit).
• Uses TCP – CIS475 (Computer Networks).
– The connectionless-oriented model.• Uses UDP – CIS475 (Computer Networks).
The Connection-Oriented Model
The connection-oriented model can be used by a process which needs to send an unformatted, uninterrupted stream of characters to the same constant destination.
For example: a remote login connection where a client system has a virtual connection to a server.
Like a phone network.
The Connectionless Model
Suppose a server wants to send a broadcast message to all its clients (and is not necessarily concerned that the clients get the message), the server can use a connectionless-oriented model.
The process sends the message to a specified network address, it then sends the next message to a different address.
Like United States Postal Service.
Addressing
When processes are communicating across a network they must know the network address of the machine that the processes are residing on.
The address essentially gives the physical location of a machine on a network.
Addresses are generally layered, representing the different levels of a network.
IP Addressing
– Across the world’s networks there is an almost universally accepted addressing standard - IP internet addressing.
– An IPv4 address consists of four decimals separated by periods.
• 134.88.14.211 - uranium’s (current) IP address.
– At the programming level, IP addresses are stored in an in_addr_t type.
IP Addressing
UNIX provides the inet_addr() system call that converts the four-decimal representation to the in_addr_t representation.
Usage#include <arpa/inet.h>
in_addr_t inet_addr(const char *ip_address);
*ip_address is in the form discussed earlier, the routine returns an address in the form of in_addr_t (a -1 if in error).
Ports
Once the address of the machine to access is known, the client process also needs to know the correct server processes to connect to.
Each server process sets and listens for connections on a specified port number.
Therefore a client process will ask for a connection to a specific machine and port.
Ports At the programming level, ports are stored as an in_port_t type.
UNIX systems expect a port to be a 16-byte unsigned int. – Our lab machines are 32-bit systems, so integers are 4
bytes. Need to convert!
#include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
Ex: in_port_t serverPortNum = htons(7000);
Sockets In all forms of communication, both the client and
server must establish their own transport end points, or sockets.– Like a wall socket: can’t get electricity to a lamp’s plug
without a socket!
These are handles used to establish a link between processes across a network.
Different types of sockets are used for different types of IPC within the same machine or on different machines.
Sockets
A specific form of socket for network communication is shown below:#include <netinet/in.h>
struct sockaddr_in{
sa_family_t sin_family; // internet address family
in_port_t sin_port; // port number
struct in_addr sin_addr; // holds the IP address
}
Creation of sockets is achieved using the socket() system call.
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain tells the call where the socket is to be used. – AF_INET - internet domain.– AF_UNIX - same UNIX machine.
type specifies connection type.– SOCK_STREAM - TCP.– SOCK_DGRAM - UDP.
protocol indicates type of communication.– SOCK_STREAM - TCP.– SOCK_DGRAM - UDP.
Returns a file descriptor for the socket.
Server-Side Binding The bind() system call associates the true network address of
a machine with a socket identifier.
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *address,
size_t add_len);
sockfd is the socket file descriptor, returned by the socket() system call.
*address is a pointer to a socket address structure. add_len is the size of the socket structure referenced by address. Returns 0 on success, -1 on failure.
Server-Side Listening
After binding and before any client system can connect to the newly created server endpoint, the server must set itself up to wait for connections.
#include <sys/sockets.h>
int listen (int sockfd, int queue_size);
sockfd is the socket file descriptor. queue_size is the number of incoming
connection requests that the server can queue.
Server-Side Accepting
When the server receives a connect() request from a client (discussed later) it has to create an entirely new socket to handle the specific communication.
The first socket is used only to establish a connection. Data isn’t passed through it.
Creation of a second socket is done using the accept() system call.
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *address,
size_t *add_len);
sockfd is the original socket file descriptor. *address is a pointer to a socket address structure. Since we
already have this info from the original socket, can set to NULL.
add_len holds the size of the socket structure referenced by address. Can also be NULL.
Returns a file descriptor to the new socket to be used for communication (-1 on failure).
A Simple Example
We will use all the system calls we have seen so far.
Server doesn’t actually do anything yet except establish itself on a socket and wait for a client connection.
Client-Side Connecting to Server
To request a connection to a server process and machine, the client uses the connect() system call.
Once the server receives this request, it will reply with its own accept() request.
#include <sys/types.h>
#include <sys/socket.h>
int connect(int c_sockfd, const struct sockaddr *address, size_t add_len);
c_sockfd is the client’s socket file descriptor.*address is a pointer to a socket address structure. This should contain the IP address and port number of the server to connect to.add_len holds the size of the socket structure referenced by address. Returns 0 on successful connection to server, -1 on failure.
The Other Half of the Example
Client simply sends a connection request to the server.– The client MUST know the internet address of
the server in order to connect!
Sending and Receiving Data Now a connection has been established between the
client and the server. We’re finally ready to communicate for IPC!
Remember, sockets have file descriptors associated with them. – Hopefully you recall from earlier labs that we can read()
and write() with file descriptors. If extra options are needed, two new system calls can
be used instead.– send() and recv().
send()#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buffer, size_t length, int flags);
sockfd is the socket file descriptor. *buffer contains the message to send. length is the size of the buffer. flags are optional parameters. We aren’t doing anything fancy, so
these can be 0.– This causes the behavior of send() to be identical to write()!
ssize_t recv(int sockfd, void *buffer, size_t length, int flags);
The recv call specifies the file descriptor to read the data from the buffer and the length of the buffer.
recv()#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buffer,
size_t length, int flags);
sockfd is the socket file descriptor. *buffer contains the destination of the received message. length is the size of buffer. flags can be 0.– This causes the behavior of recv() to be identical to read()!
The recv call specifies the file descriptor to read the data from the buffer and the length of the buffer.
Continuing Our Example
Let’s look at a complete example.– Client accepts a lowercase character from user at
command line.– Client sends lowercase letter to server.– Server will convert the letter to uppercase and send
it back to client.– Client will then output the new character to user.*Note that the user does not interact directly with the server!
Closing the Connection
It is important to deal with closing the socket connection.
Since a socket is a two-way communication mechanism, it is impossible to predict whether a process will be trying to read or write when a break in the communication occurs.
If a process attempts to write() or send() data to a socket which has become disconnected it will receive the SIGPIPE signal, which can be dealt with through a signal handler.
If read() or recv() returns zero, then the connection has been closed by the other side.
If using the connection-oriented model, the socket close is blocked until the current data transfer is complete.
If the connectionless model is in use, the socket is closed immediately.
Closing the Connection
Completing Our Example Client and server both close their sockets if the
other process dies. For completeness, some things have been
changed from previous examples.– Client supports multiple input characters.
– Server now supports multiple clients.
Following complete samples are available online:www.cis.umassd.edu/~jplante/cis370/lab10/samples/server.c
www.cis.umassd.edu/~jplante/cis370/lab10/samples/client.c
The Connectionless Model
Up to this point, we’ve looked only at the connection-oriented model.
The remaining slides are for educational purposes only and are optional.
The following slides are NOT necessary for completing today’s assignment!
The Connectionless Model
Unlike the connection-oriented approach, packets transmitted between the client and server will arrive at their destination in an indeterminate order.
A process wishing to send or receive messages across a network must create its own local socket and bind() its own network address to that socket.– This means clients need to bind() too!
Sending and Receiving Messages In the connectionless model, the processes
aren’t directly connected to eachother. Processes can send/recv data from any
process on any machine.– This is how the Internet works!
Processes don’t automatically know who is sending messages to them.– Cannot use send() and recv()!
ssize_t sendto(int sockfd, const void *message,
size_t length, int flags, struct sockaddr *send_addr, size_t *add_len);
sockfd is the socket file descriptor. *message contains the data to send. length is the size of message. flags can be 0. *send_addr contains the information of the recipient
including its IP address and port number. *add_len is the size of send_addr.
ssize_t recvfrom(int sockfd, void *message, size_t length, int flags, struct sockaddr *send_addr, size_t *add_len);
sockfd is the socket file descriptor. *message is the buffer for received data. length is the size of message. flags can be 0. *send_addr contains the information of the sender
including its IP address and port number. *add_len is the size of send_addr.
The Difference?
In both models the server has to create a socket and bind its local address to that socket.
In the connection model the server must then start to listen for the incoming connection. This step is not necessary in the connectionless model as the client will do more of the work.
The Difference?
From a client perspective, in the connection model, the client just connects to the server.
In the connectionless model, the client must create a socket and bind its local address to that socket.
The Difference?
Different system calls are normally used to transmit data.
The sendto() and recvfrom() calls are normally used in the connectionless model so that the server can retrieve information about the sender of the message and reply accordingly.