Socket Protocols
Where the underlying transport mechanism allows for more than one protocol to provide the requested socket type, you can select a specific protocol for a socket.
Creating a Socket
The socket system call creates a socket and returns a descriptor that can be used for accessing the socket.
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
The socket created is one end point of a communication channel. The domain parameter specifies the address family, the type parameter specifies the type of communication to be used with this socket, and protocol specifies the protocol to be employed.
Domains include the following:
AF_UNIX UNIX internal (file system sockets)
AF_INET ARPA Internet protocols (UNIX network sockets)
AF_ISO ISO standard protocols
AF_NS Xerox Network Systems protocols
AF_IPX Novell IPX protocol
AF_APPLETALK Appletalk DDS
The most common socket domains are AF_UNIX, which is used for local sockets implemented via the UNIX and Linux file systems, and AF_INET, which is used for UNIX network sockets. The AF_INET sockets may be used by programs communicating across a TCP/IP network including the Internet. The Windows Winsock interface also provides access to this socket domain.
The socket parameter type specifies the communication characteristics to be used for the new socket. Possible values include SOCK_STREAM and SOCK_DGRAM.
SOCK_STREAM is a sequenced, reliable, connection-based two-way byte stream. For an AF_INET domain socket, this is provided by default by a TCP connection that is established between the two end points of the stream socket when it’s connected. Data may be passed in both directions along the socket connection. The TCP protocols include facilities to fragment and reassemble long messages and to retransmit any parts that may be lost in the network.
SOCK_DGRAM is a datagram service. You can use this socket to send messages of a fixed (usually small) maximum size, but there’s no guarantee that the message will be delivered or that messages won’t be reordered in the network. For AF_INET sockets, this type of communication is provided by UDP datagrams.
The protocol used for communication is usually determined by the socket type and domain. There is normally no choice. The protocol parameter is used where there is a choice. 0 selects the default protocol, which we’ll use in all our examples.
The socket system call returns a descriptor that is in many ways similar to a low-level file descriptor. When the socket has been connected to another end-point socket, you may use the read and write system calls with the descriptor to send and receive data on the socket. The close system call is used to end a socket connection.
Socket Addresses
Each socket domain requires its own address format. For an AF_UNIX socket, the address is described by a structure, sockaddr_un, defined in the sys/un.h include file.
struct sockaddr_un {
sa_family_t
sun_family;
char
sun_path[];
};
/* AF_UNIX */
/* pathname */
So that addresses of different types may be passed to the socket-handling system calls, each address format is described by a similar structure that begins with a field (in this case, sun_family) that specifies the address type (the socket domain). In the AF_UNIX domain, the address is specified by a filename in the sun_path field of the structure.
On current Linux systems, the type sa_family_t, defined by X/Open as being declared in sys/un.h, is taken to be a short. Also, the pathname specified in sun_path is limited in size (Linux specifies 108 characters; others may use a manifest constant such as UNIX_MAX_PATH). Because address structures
may vary in size, many socket calls require or provide as an output a length to be used for copying the particular address structure.
In the AF_INET domain, the address is specified using a structure called sockaddr_in, defined in netinet/in.h, which contains at least these members:
struct sockaddr_in {
short int
unsigned short int
struct in_addr
};
sin_family;
sin_port;
sin_addr;
/* AF_INET */
/* Port number */
/* Internet address */
The IP address structure, in_addr, is defined as follows:
struct in_addr {
unsigned long int
};
s_addr;
The four bytes of an IP address constitute a single 32-bit value. An AF_INET socket is fully described by its domain, IP address, and port number. From an application’s point of view, all sockets act like file descriptors and are addressed by a unique integer value.
Naming a Socket
To make a socket (as created by a call to socket) available for use by other processes, a server program needs to give the socket a name. Thus, AF_UNIX sockets are associated with a file system pathname, as you saw in the server1 example. AF_INET sockets are associated with an IP port number.
#include <sys/socket.h>
int bind(int socket, const struct sockaddr *address, size_t address_len);
The bind system call assigns the address specified in the parameter, address, to the unnamed socket associated with the file descriptor socket. The length of the address structure is passed as address_len. The length and format of the address depend on the address family. A particular address structure pointer will need to be cast to the generic address type (struct sockaddr *) in the call to bind. On successful completion, bind returns 0. If it fails, it returns -1 and sets errno to one of the following.
EBADF The file descriptor is invalid.
ENOTSOCK The file descriptor doesn’t refer to a socket.
EINVAL The file descriptor refers to an already-named socket.
EADDRNOTAVAIL The address is unavailable.
EADDRINUSE The address has a socket bound to it already. There are some more values for AF_UNIX sockets:
EACCESS Can’t create the file system name due to permissions.
ENOTDIR, ENAMETOOLONG Indicates a poor choice of filename.
Creating a Socket Queue
To accept incoming connections on a socket, a server program must create a queue to store pending requests. It does this using the listen system call.
#include <sys/socket.h>
int listen(int socket, int backlog);
A Linux system may limit the maximum number of pending connections that may be held in a queue. Subject to this maximum, listen sets the queue length to backlog. Incoming connections up to this queue length are held pending on the socket; further connections will be refused and the client’s connection will fail. This mechanism is provided by listen to allow incoming connections to be held pending while a server program is busy dealing with a previous client. A value of 5 for backlog is very common. The listen function will return 0 on success or -1 on error. Errors include EBADF, EINVAL, and ENOTSOCK, as for the bind system call.
Accepting Connections
Once a server program has created and named a socket, it can wait for connections to be made to the socket by using the accept system call.
#include <sys/socket.h>
int accept(int socket, struct sockaddr *address, size_t *address_len);
The accept system call returns when a client program attempts to connect to the socket specified by the parameter socket. The client is the first pending connection from that socket’s queue. The accept function creates a new socket to communicate with the client and returns its descriptor. The new socket will have the same type as the server listen socket. The socket must have previously been named by a call to bind and had a connection queue allocated by listen. The address of the calling client will be placed in the sockaddr structure pointed to by address. A null pointer may be used here if the client address isn’t of interest.
The address_len parameter specifies the length of the client structure. If the client address is longer than this value, it will be truncated. Before calling accept, address_len must be set to the expected address length. On return, address_len will be set to the actual length of the calling client’s address
structure.
If there are no connections pending on the socket’s queue, accept will block (so that the program won’t continue) until a client makes a connection. You may change this behavior by using the O_NONBLOCK flag on the socket file descriptor, using the fcntl function like this:
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, O_NONBLOCK|flags);
The accept function returns a new socket file descriptor when there is a client connection pending or -1 on error. Possible errors are similar to those for bind and listen, with the addition of EWOULDBLOCK, where O_NONBLOCK has been specified and there are no pending connections. The error EINTR will occur if the process is interrupted while blocked in accept.
Requesting Connections
Client programs connect to servers by establishing a connection between an unnamed socket and the server listen socket. They do this by calling connect.
#include <sys/socket.h>
int connect(int socket, const struct sockaddr *address, size_t address_len);
The socket specified by the parameter socket is connected to the server socket specified by the parameter address, which is of length address_len. The socket must be a valid file descriptor obtained by a call to socket.
If it succeeds, connect returns 0, and -1 is returned on error. Possible errorsthis time include the following:
EBADF An invalid file descriptor was passed in socket.
EALREADY A connection is already in progress for this socket.
ETIMEDOUT A connection timeout has occurred.
ECONNREFUSED The requested connection was refused by the server.
If the connection can’t be set up immediately, connect will block for an unspecified timeout period.
Once this timeout has expired, the connection will be aborted and connect will fail. However, if the call to connect is interrupted by a signal that is handled, the connect call will fail (with errno set to EINTR), but the connection attempt won’t be aborted but rather will be set up asynchronously. As with accept, the blocking nature of connect may be altered by setting the O_NONBLOCK flag on the file descriptor. In this case, if the connection can’t be made immediately, connect will fail with errno
set to EINPROGRESS and the connection will be made asynchronously.
While asynchronous connections can be tricky to handle, you can use a call to select on the socket file descriptor to indicate that the socket is ready for writing.
Closing a Socket
You can terminate a socket connection at the server and client by calling close, just as you would for low-level file descriptors. You should always close the socket at both ends. For the server, you should do this when read returns zero, but the close call could block if the socket has untransmitted data, is of a connection-oriented type, and has the SOCK_LINGER option set.
Where the underlying transport mechanism allows for more than one protocol to provide the requested socket type, you can select a specific protocol for a socket.
Creating a Socket
The socket system call creates a socket and returns a descriptor that can be used for accessing the socket.
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
The socket created is one end point of a communication channel. The domain parameter specifies the address family, the type parameter specifies the type of communication to be used with this socket, and protocol specifies the protocol to be employed.
Domains include the following:
AF_UNIX UNIX internal (file system sockets)
AF_INET ARPA Internet protocols (UNIX network sockets)
AF_ISO ISO standard protocols
AF_NS Xerox Network Systems protocols
AF_IPX Novell IPX protocol
AF_APPLETALK Appletalk DDS
The most common socket domains are AF_UNIX, which is used for local sockets implemented via the UNIX and Linux file systems, and AF_INET, which is used for UNIX network sockets. The AF_INET sockets may be used by programs communicating across a TCP/IP network including the Internet. The Windows Winsock interface also provides access to this socket domain.
The socket parameter type specifies the communication characteristics to be used for the new socket. Possible values include SOCK_STREAM and SOCK_DGRAM.
SOCK_STREAM is a sequenced, reliable, connection-based two-way byte stream. For an AF_INET domain socket, this is provided by default by a TCP connection that is established between the two end points of the stream socket when it’s connected. Data may be passed in both directions along the socket connection. The TCP protocols include facilities to fragment and reassemble long messages and to retransmit any parts that may be lost in the network.
SOCK_DGRAM is a datagram service. You can use this socket to send messages of a fixed (usually small) maximum size, but there’s no guarantee that the message will be delivered or that messages won’t be reordered in the network. For AF_INET sockets, this type of communication is provided by UDP datagrams.
The protocol used for communication is usually determined by the socket type and domain. There is normally no choice. The protocol parameter is used where there is a choice. 0 selects the default protocol, which we’ll use in all our examples.
The socket system call returns a descriptor that is in many ways similar to a low-level file descriptor. When the socket has been connected to another end-point socket, you may use the read and write system calls with the descriptor to send and receive data on the socket. The close system call is used to end a socket connection.
Socket Addresses
Each socket domain requires its own address format. For an AF_UNIX socket, the address is described by a structure, sockaddr_un, defined in the sys/un.h include file.
struct sockaddr_un {
sa_family_t
sun_family;
char
sun_path[];
};
/* AF_UNIX */
/* pathname */
So that addresses of different types may be passed to the socket-handling system calls, each address format is described by a similar structure that begins with a field (in this case, sun_family) that specifies the address type (the socket domain). In the AF_UNIX domain, the address is specified by a filename in the sun_path field of the structure.
On current Linux systems, the type sa_family_t, defined by X/Open as being declared in sys/un.h, is taken to be a short. Also, the pathname specified in sun_path is limited in size (Linux specifies 108 characters; others may use a manifest constant such as UNIX_MAX_PATH). Because address structures
may vary in size, many socket calls require or provide as an output a length to be used for copying the particular address structure.
In the AF_INET domain, the address is specified using a structure called sockaddr_in, defined in netinet/in.h, which contains at least these members:
struct sockaddr_in {
short int
unsigned short int
struct in_addr
};
sin_family;
sin_port;
sin_addr;
/* AF_INET */
/* Port number */
/* Internet address */
The IP address structure, in_addr, is defined as follows:
struct in_addr {
unsigned long int
};
s_addr;
The four bytes of an IP address constitute a single 32-bit value. An AF_INET socket is fully described by its domain, IP address, and port number. From an application’s point of view, all sockets act like file descriptors and are addressed by a unique integer value.
Naming a Socket
To make a socket (as created by a call to socket) available for use by other processes, a server program needs to give the socket a name. Thus, AF_UNIX sockets are associated with a file system pathname, as you saw in the server1 example. AF_INET sockets are associated with an IP port number.
#include <sys/socket.h>
int bind(int socket, const struct sockaddr *address, size_t address_len);
The bind system call assigns the address specified in the parameter, address, to the unnamed socket associated with the file descriptor socket. The length of the address structure is passed as address_len. The length and format of the address depend on the address family. A particular address structure pointer will need to be cast to the generic address type (struct sockaddr *) in the call to bind. On successful completion, bind returns 0. If it fails, it returns -1 and sets errno to one of the following.
EBADF The file descriptor is invalid.
ENOTSOCK The file descriptor doesn’t refer to a socket.
EINVAL The file descriptor refers to an already-named socket.
EADDRNOTAVAIL The address is unavailable.
EADDRINUSE The address has a socket bound to it already. There are some more values for AF_UNIX sockets:
EACCESS Can’t create the file system name due to permissions.
ENOTDIR, ENAMETOOLONG Indicates a poor choice of filename.
Creating a Socket Queue
To accept incoming connections on a socket, a server program must create a queue to store pending requests. It does this using the listen system call.
#include <sys/socket.h>
int listen(int socket, int backlog);
A Linux system may limit the maximum number of pending connections that may be held in a queue. Subject to this maximum, listen sets the queue length to backlog. Incoming connections up to this queue length are held pending on the socket; further connections will be refused and the client’s connection will fail. This mechanism is provided by listen to allow incoming connections to be held pending while a server program is busy dealing with a previous client. A value of 5 for backlog is very common. The listen function will return 0 on success or -1 on error. Errors include EBADF, EINVAL, and ENOTSOCK, as for the bind system call.
Accepting Connections
Once a server program has created and named a socket, it can wait for connections to be made to the socket by using the accept system call.
#include <sys/socket.h>
int accept(int socket, struct sockaddr *address, size_t *address_len);
The accept system call returns when a client program attempts to connect to the socket specified by the parameter socket. The client is the first pending connection from that socket’s queue. The accept function creates a new socket to communicate with the client and returns its descriptor. The new socket will have the same type as the server listen socket. The socket must have previously been named by a call to bind and had a connection queue allocated by listen. The address of the calling client will be placed in the sockaddr structure pointed to by address. A null pointer may be used here if the client address isn’t of interest.
The address_len parameter specifies the length of the client structure. If the client address is longer than this value, it will be truncated. Before calling accept, address_len must be set to the expected address length. On return, address_len will be set to the actual length of the calling client’s address
structure.
If there are no connections pending on the socket’s queue, accept will block (so that the program won’t continue) until a client makes a connection. You may change this behavior by using the O_NONBLOCK flag on the socket file descriptor, using the fcntl function like this:
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, O_NONBLOCK|flags);
The accept function returns a new socket file descriptor when there is a client connection pending or -1 on error. Possible errors are similar to those for bind and listen, with the addition of EWOULDBLOCK, where O_NONBLOCK has been specified and there are no pending connections. The error EINTR will occur if the process is interrupted while blocked in accept.
Requesting Connections
Client programs connect to servers by establishing a connection between an unnamed socket and the server listen socket. They do this by calling connect.
#include <sys/socket.h>
int connect(int socket, const struct sockaddr *address, size_t address_len);
The socket specified by the parameter socket is connected to the server socket specified by the parameter address, which is of length address_len. The socket must be a valid file descriptor obtained by a call to socket.
If it succeeds, connect returns 0, and -1 is returned on error. Possible errorsthis time include the following:
EBADF An invalid file descriptor was passed in socket.
EALREADY A connection is already in progress for this socket.
ETIMEDOUT A connection timeout has occurred.
ECONNREFUSED The requested connection was refused by the server.
If the connection can’t be set up immediately, connect will block for an unspecified timeout period.
Once this timeout has expired, the connection will be aborted and connect will fail. However, if the call to connect is interrupted by a signal that is handled, the connect call will fail (with errno set to EINTR), but the connection attempt won’t be aborted but rather will be set up asynchronously. As with accept, the blocking nature of connect may be altered by setting the O_NONBLOCK flag on the file descriptor. In this case, if the connection can’t be made immediately, connect will fail with errno
set to EINPROGRESS and the connection will be made asynchronously.
While asynchronous connections can be tricky to handle, you can use a call to select on the socket file descriptor to indicate that the socket is ready for writing.
Closing a Socket
You can terminate a socket connection at the server and client by calling close, just as you would for low-level file descriptors. You should always close the socket at both ends. For the server, you should do this when read returns zero, but the close call could block if the socket has untransmitted data, is of a connection-oriented type, and has the SOCK_LINGER option set.
No comments:
Post a Comment