Practical 2
Practical 2
DESCRIPTION:
Socket
Connection-oriented service
Connection less service
Connection oriented model defines a reliable delivery service. The figure shows a
sequence of system calls for connection oriented communication. The server begins by carrying
out a passive open as follows. The socket call creates a TCP socket. The bind call then binds the
well-known port number of the server to the socket. The listen call turns the socket into a
listening socket that can accept incoming connections from clients. Finally, the accept call puts
the server process to sleep until the arrival of a client connection. The client does an active open.
The socket call creates a socket on the client side, and the connect call establishes the TCP
connection to the server with the specified destination socket address. When the TCP connection
is completed, the accept function at the server wakes up and returns the descriptor for the given
connection, namely, the source IP address, the source port number, destination IP address and
destination port number. The client and server are now ready to exchange information.
In a connection –less mode an application program sends its data immediately without
waiting for connection establishment. As a result the application program may waste its time by
sending data when the other end is not ready to accept it. Moreover, data may not arrive at the
other end if the network decides to discards it. If data arrives at the destination, it may not arrive
in the same order as it was transmitted.
The connectionless mode is often said to provide best effort service, since the network
would try its best to deliver the information but cannot guarantee the delivery.
The figure shows the sequence of system calls for a connectionless communication. No
connection is established prior to data transfer. The recvfrom call returns when a Complete UDP
data gram has been received.
Types of sockets
Stream sockets
Datagram sockets and
Raw sockets
Stream sockets are used for stream connections, i.e. connections that exist for a long duration.
TCP connections use stream sockets.
Datagram sockets are used for short-term connections that transfer a single packet across the
network before terminating. The UDP protocol uses such sockets, due to its connection-less
nature.
Raw sockets are used to access low-level protocols directly, bypassing the higher protocols.
They are the means for a programmer to use the IP protocol, or the physical layer of the network,
directly. Raw sockets can therefor be used to implement new protocols on top of the low-level
protocols. Naturally, they are out of our scope.
socket() creates an endpoint for communication and returns a file descriptor for the socket.
socket() takes three arguments:
domain, which specifies the protocol family of the created socket. For example:
o PF_INET for network protocol IPv4 or
o PF_INET6 for IPv6.
o PF_UNIX for local socket (using a file).
type, one of:
o SOCK_STREAM (reliable stream-oriented service or Stream Sockets)
o SOCK_DGRAM (datagram service or Datagram Sockets)
o SOCK_SEQPACKET (reliable sequenced packet service), or
o SOCK_RAW (raw protocols atop the network layer).
protocol specifying the actual transport protocol to use. The most common are
IPPROTO_TCP, IPPROTO_SCTP, IPPROTO_UDP, IPPROTO_DCCP. These protocols
are specified in <netinet/in.h>. The value “0” may be used to select a default protocol
from the selected domain and type.
The function returns -1 if an error occurred. Otherwise, it returns an integer representing the
newly-assigned descriptor.
Prototype
bind() assigns a socket an address. When a socket is created using socket(), it is only given a
protocol family, but not assigned an address. This association with an address must be performed
with the bind() system call before the socket can accept connections to other hosts. bind() takes
three arguments:
Prototype
listen()
After a socket has been associated with an address, listen() prepares it for incoming connections.
However, this is only necessary for the stream-oriented (connection-oriented) data modes, i.e.,
for socket types (SOCK_STREAM, SOCK_SEQPACKET). listen() requires two arguments:
Prototype
When an application is listening for stream-oriented connections from other hosts, it is notified
of such events (cf. select() function) and must initialize the connection using the accept()
function. Accept() creates a new socket for each connection and removes the connection from
the listen queue. It takes the following arguments:
sockfd, the descriptor of the listening socket that has the connection queued.
cliaddr, a pointer to a sockaddr structure to receive the client's address information.
addrlen, a pointer to a socklen_t location that specifies the size of the client address
structure passed to accept(). When accept() returns, this location indicates how many
bytes of the structure were actually used.
The accept() function returns the new socket descriptor for the accepted connection, or -1 if an
error occurs. All further communication with the remote host now occurs via this new socket.
Datagram sockets do not require processing by accept() since the receiver may immediately
respond to the request using the listening socket.
Prototype
The connect() system call connects a socket, identified by its file descriptor, to a remote host
specified by that host's address in the argument list.
Certain types of sockets are connectionless, most commonly user datagram protocol sockets. For
these sockets, connect takes on a special meaning: the default target for sending and receiving
data gets set to the given address, allowing the use of functions such as send() and recv() on
connectionless sockets.
connect() returns an integer representing the error code: 0 represents success, while -1 represents
an error.
Prototype
After a connection is established, there are several ways to send information over the socket.
read()
The most common way of reading data from a socket is using the read () system call, which is
defined like this:
Note that read() might read less than the number of bytes we requested, due to unavailability of
buffer space in the system.
write()
The most common way of writing data to a socket is using the write() system call, which is
defined like this:
Note that the system keeps internal buffers, and the write system call write data to those buffers,
not necessarily directly to the network. Thus, a successful write() doesn't mean the data arrived at
the other end, or was even sent onto the network. Also, it could be that only some of the bytes
were written, and not the actual number we requested. It is up to us to try to send the data again
later on, when it's possible, and we'll show several methods for doing just that.
sendto() and recvfrom() for DATAGRAM (UDP)
Since datagram sockets aren’t connected to a remote host, we need to give the destination
address before we send a packet.
The prototype is:
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const
This call is basically the same as the call to send() with the addition of two other pieces of
information.
to is a pointer to a struct sockaddr (which you’ll probably have as a struct sockaddr_in
and cast it at the last minute) which contains the destination IP address and port.
tolen can simply be set to sizeof(struct sockaddr).
Just like with send(), sendto() returns the number of bytes actually sent (which, again,
might be less than the number of bytes you told it to send!), or -1 on error.
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct
Again, this is just like recv() with the addition of a couple fields.
from is a pointer to a local struct sockaddr that will be filled with the IP address and port
of the originating machine.
fromlen is a pointer to a local int that should be initialized to sizeof(struct sockaddr).
When the function returns, fromlen will contain the length of the address actually stored
in from. recvfrom() returns the number of bytes received, or -1 on error (with errno set
accordingly).
Remember, if you connect() a datagram socket, you can then simply use send() and recv()
for all your transactions.
The socket itself is still a datagram socket and the packets still use UDP, but the socket
interface will automatically add the destination and source information for you.
Socket Address
struct sockaddr_in
struct sockaddr_in {
u_char sin_len;
};
The sin_family field is the address family (always AF_INET for TCP and UDP).
The sin_port field is the port number, and the sin_addr field is the Internet address. The
sin_zero field is reserved, and you must set it to hexadecimal zeroes.
Data type struct in_addr - this data type is used in certain contexts to contain an Internet
host address. It has just one field, named s_addr, which records the host address number
as an unsigned long int.
sockaddr_in is a "specialized" sockaddr.
sin_addr could be u_long.
sin_addr is 4 bytes and 8 bytes are unused.
sockaddr_in is used to specify an endpoint.
The sin_port and sin_addr must be in Network Byte Order.
bzero()
The bzero function writes specified number of null bytes into specified destination
Prototype
Byte Ordering
The network addresses are need to formed using the network byte order. Luckily, most
networking functions accept addresses in host byte order, and return their results in network byte
order. This means only a few fields will need conversions. These will include the port numbers
only, as the addresses are already supplied by the system.
Close()
The normal LINUX close system call is also used to close a socket.
Prototype
Address Formation
Forming addresses for Internet protocols is done using a structure named sockaddr_in, whose
definition, as given in the file /usr/include/netinet/in.h, is as follows:
struct sockaddr_in {
short int sin_family; /* Address family */
unsigned short sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
sin_family: Family of protocols for this address. We will want the Internet family.
sin_port: The port part of the address.
sin_addr: The IP number part of the address.
Pad: This will be explained in the next section.
The command that is used to compile a C program in UNIX systems that support C compiler is
cc filename.c
Lets assume there is a file named 'single_main.c' that is to be compiled. This is using a command
line similar to this: cc single_main.c
The command that is used to execute the resulting program of the compiler in UNIX systems is
./ filename Eg. ./single_main
RESULT:
Thus the Socket programming and Client - Server model concepts under UNIX operating
systems has been studied successfully.