Unix Domain Protocols

来源:互联网 发布:郭富城 小美 知乎 编辑:程序博客网 时间:2024/05/22 05:34

The Unix domain protocols are not an actual protocol suite, but a way of performing client/server communication on a single host using the same API that is used for clients and servers on different hosts.

Two types of sockets are provided in the Unix domain: stream sockets (similar to TCP) and datagram sockets (similar to UDP).

  1. Unix domain sockets are often twice as fast as a TCP socket when both peers are on the same host
  2. Unix domain sockets are used when passing descriptors between processes on the same host.
  3. Newer implementations of Unix domain sockets provide the client's credentials (user ID and group IDs) to the server, which can provide additional security checking.

Unix domain socket address structure

<sys/un.h>struct sockaddr_un {sa_family_t sun_family; /* AF_LOCAL */char sun_path[104]; /* null-terminated pathname */};

The pathname stored in the sun_path array must be null-terminated. The macro SUN_LEN is provided and it takes a pointer to a sockaddr_un structure and returns the length of the structure, including the number of non-null bytes in the pathname. The unspecified address is indicated by a null string as the pathname, that is, a structure with sun_path[0]
equal to 0. This is the Unix domain equivalent of the IPv4 INADDR_ANY constant and the IPv6 IN6ADDR_ANY_INIT constant.

int sockfd = Socket(AF_LOCAL, SOCK_STREAM, 0);unlink(argv[1]);struct sockaddr_un addr1;bzero(&addr1, sizeof(addr1));addr1.sun_family = AF_LOCAL;strncpy(addr1.sun_path, argv[1], sizeof(addr1.sun_path) - 1);Bind(sockfd, (SA *) &addr1, SUN_LEN(&addr1));

The pathname that we bind to the socket is the command-line argument. But the bind will fail if the pathname already exists in the filesystem. Therefore, we call unlink to delete
the pathname, in case it already exists. If it does not exist, unlink returns an error, which we ignore.

#include <sys/socket.h>
int socketpair(int family, int type, int protocol, int sockfd[2]);
Returns: nonzero if OK, -1 on error

The socketpair function creates two sockets that are then connected together. This function applies only to Unix domain sockets.

The family must be AF_LOCAL and the protocol must be 0. The type, however, can be either SOCK_STREAM or SOCK_DGRAM. The two socket descriptors that are created are returned as sockfd[0] and sockfd[1].

The two created sockets are unnamed; that is, there is no implicit bind involved.

Socket Functions

There are several differences and restrictions in the socket functions when using Unix domain sockets.

  1. The default file access permissions for a pathname created by bind should be 0777 (read, write, and execute by user, group, and other), modified by the current umask
    value.
  2. The pathname associated with a Unix domain socket should be an absolute pathname, not a relative pathname.
  3. The pathname specified in a call to connect must be a pathname that is currently bound to an open Unix domain socket of the same type (stream or datagram).
    Errors occur if: (i) the pathname exists but is not a socket; (ii) the pathname exists and is a socket, but no open socket descriptor is associated with the pathname; or
    (iii) the pathname exists and is an open socket, but is of the wrong type (that is, a Unix domain stream socket cannot connect to a pathname associated with a Unix
    domain datagram socket, and vice versa).
  4. The permission testing associated with the connect of a Unix domain socket is the same as if open had been called for write-only access to the pathname.
  5. Unix domain stream sockets are similar to TCP sockets: They provide a byte stream interface to the process with no record boundaries.
  6. If a call to connect for a Unix domain stream socket finds that the listening socket's queue is full, ECONNREFUSED is returned immediately. This differs from TCP: The TCP listener ignores an arriving SYN if the socket's queue is full, and the TCP connector retries by sending the SYN several times.
  7. Unix domain datagram sockets are similar to UDP sockets: They provide an unreliable datagram service that preserves record boundaries.
  8. Unlike UDP sockets, sending a datagram on an unbound Unix domain datagram socket does not bind a pathname to the socket. (Recall that sending a UDP
    datagram on an unbound UDP socket causes an ephemeral port to be bound to the socket.) This means the receiver of the datagram will be unable to send a reply
    unless the sender has bound a pathname to its socket. Similarly, unlike TCP and UDP, calling connect for a Unix domain datagram socket does not bind a pathname
    to the socket.

Passing Descriptors

  1. A child sharing all the open descriptors with the parent after a call to fork
  2. All descriptors normally remaining open when exec is called

The steps involved in passing a descriptor between two processes are then as follows:

  1. Create a Unix domain socket, either a stream socket or a datagram socket.
    If the goal is to fork a child and have the child open the descriptor and pass the descriptor back to the parent, the parent can call socketpair to create a stream pipe that can be used to exchange the descriptor.
    If the processes are unrelated, the server must create a Unix domain stream socket and bind a pathname to it, allowing the client to connect to that socket. The client
    can then send a request to the server to open some descriptor and the server can pass back the descriptor across the Unix domain socket. Alternately, a Unix domain
    datagram socket can also be used between the client and server, but there is little advantage in doing this, and the possibility exists for a datagram to be discarded.
    We will use a stream socket between the client and server.
  2. One process opens a descriptor by calling any of the Unix functions that returns a descriptor: open, pipe, mkfifo, socket, or accept, for example. Any type of descriptor can be passed from one process to another, which is why we call the technique "descriptor passing" and not "file descriptor passing."
  3. The sending process builds a msghdr structure containing the descriptor to be passed. POSIX specifies that the descriptor be sent as ancillary data (the msg_control member of the msghdr structure). The sending process calls sendmsg to send the descriptor across the Unix domain socket from Step 1. At this point, we say that the descriptor is "in flight." Even if the sending process closes the descriptor after calling sendmsg, but before the receiving process calls recvmsg (in the next step), the descriptor remains open for the receiving process. Sending a descriptor increments the descriptor's reference count by one.
  4. The receiving process calls recvmsg to receive the descriptor on the Unix domain socket from Step 1. It is normal for the descriptor number in the receiving process
    to differ from the descriptor number in the sending process. Passing a descriptor is not passing a descriptor number, but involves creating a new descriptor in the
    receiving process that refers to the same file table entry within the kernel as the descriptor that was sent by the sending process.

the MSG_PEEK flag should be avoided with recvmsg if a descriptor is expected, as the result is unpredictable.


0 0
原创粉丝点击