Advanced Programming in the UNIX Environment: Second Edition [Electronic resources]

W. Richard Stevens; Stephen A. Rago

نسخه متنی -صفحه : 369/ 251
نمايش فراداده

16.2. Socket Descriptors

A socket is an abstraction of a communication endpoint. Just as they would use file descriptors to access a file, applications use socket descriptors to access sockets. Socket descriptors are implemented as file descriptors in the UNIX System. Indeed, many of the functions that deal with file descriptors, such as read and write, will work with a socket descriptor.

To create a socket, we call the socket function.

#include <sys/socket.h> int socket(int

domain , int

type , int

protocol );

Returns: file (socket) descriptor if OK, 1 on error

The

domain argument determines the nature of the communication, including the address format (described in more detail in the next section). Section 17.3. Most systems define the AF_LOCAL domain also, which is an alias for AF_UNIX. The AF_UNSPEC domain is a wildcard that represents "any" domain. Historically, some platforms provide support for additional network protocols, such as AF_IPX for the NetWare protocol family, but domain constants for these protocols are not defined by the POSIX.1 standard.

The

type argument determines the type of the socket, which further determines the communication characteristics. The socket types defined by POSIX.1 are summarized in Section 3.3)

deallocates the socket

dup, dup2 (Section 3.12)

duplicates the file descriptor as normal

fchdir (Section 4.22)

fails with errno set to ENOTDIR

fchmod (Section 4.9)

unspecified

fchown (Section 4.11)

implementation defined

fcntl (Section 3.14)

some commands supported, including F_DUPFD, F_GETFD, F_GETFL, F_GETOWN, F_SETFD, F_SETFL, and F_SETOWN

fdatasync, fsync (Section 3.13)

implementation defined

fstat (Section 4.2)

some stat structure members supported, but how left up to the implementation

ftruncate (Section 4.13)

unspecified

getmsg, getpmsg (Section 14.4)

works if sockets are implemented with STREAMS (i.e., on Solaris)

ioctl (Section 3.15)

some commands work, depending on underlying device driver

lseek (Section 3.6)

implementation defined (usually fails with errno set to ESPIPE)

mmap (Section 14.9)

unspecified

poll (Section 14.5.2)

works as expected

putmsg, putpmsg (Section 14.4)

works if sockets are implemented with STREAMS (i.e., on Solaris)

read (Section 3.7) and readv (Section 14.7)

equivalent to recv (Section 16.5) without any flags

select (Section 14.5.1)

works as expected

write (Section 3.8) and writev (Section 14.7)

equivalent to send (Section 16.5) without any flags

Communication on a socket is bidirectional. We can disable I/O on a socket with the shutdown function.

#include <sys/socket.h> int shutdown (int

sockfd , int

how );

Returns: 0 if OK, 1 on error

If

how is SHUT_RD, then reading from the socket is disabled. If

how is SHUT_WR, then we can't use the socket for transmitting data. We can use SHUT_RDWR to disable both data transmission and reception.

Given that we can close a socket, why is shutdown needed? There are several reasons. First, close will deallocate the network endpoint only when the last active reference is closed. This means that if we duplicate the socket (with dup, for example), the socket won't be deallocated until we close the last file descriptor referring to it. The shutdown function allows us to deactivate a socket independently of the number of active file descriptors referencing it. Second, it is sometimes convenient to shut a socket down in one direction only. For example, we can shut a socket down for writing if we want the process we are communicating with to be able to determine when we are done transmitting data, while still allowing us to use the socket to receive data sent to us by the process.