IPC Using Socketpair

As a warmup, we begin our exploration of sockets with the generation of a pair of UNIX domain sockets. The socketpair call, shown in Table 10.1, is used to create the pair of sockets.

The socketpair call takes four arguments. The first argument, d , is an integer value that specifies the domain. In general, the domains for socket-based calls should be specified as one of the protocol family-defined constants found in the header file . As in previous examples, the programmer does not directly include this file, since the file, which must be included, includes this more system-specific header file. When we look in the file, we find two sets of similar defined constants. One set of constants begins with AF_ (denoting address family) and the second set begins with PF_ (indicating protocol family). At one time the PF_ constants were defined in terms of the AF_ constants. Now the AF_ set of constants is defined in terms of the PF_ constants. This mishmash occurs as the concept of address families preceded that of protocol families. As we are heading toward the use of protocol families, the PF_ designated constants are more appropriate to use when generating a socket. The current set of all defined protocol families, as found in the file, is shown in Table 10.2.

Table 10.1. Summary of the socketpair System Call

Include File(s)

Manual Section

2

Summary

int socketpair( int d, int type, int protocol, int sv[2] );

Return

Success

Failure

Sets errno

0 and two open socket descriptors

-1

Yes

Table 10.2. Protocol Family Constants.

Constant

Value

Reference

PF_UNSPEC

Unspecified.

PF_LOCAL

1

Local to host (pipes and file-domain).

PF_UNIX

PF_LOCAL

Old BSD name for PF_LOCAL.

PF_FILE

PF_LOCAL

Another nonstandard name for PF_LOCAL.

PF_INET

2

IP protocol family.

PF_AX25

3

Amateur Radio AX.25.

PF_IPX

4

Novell Internet Protocol.

PF_APPLETALK

5

Appletalk DDP.

PF_NETROM

6

Amateur radio NetROM.

PF_BRIDGE

7

Multiprotocol bridge.

PF_ATMPVC

8

ATM PVCs.

PF_X25

9

Reserved for X.25 project.

PF_INET6

10

IP version 6.

PF_ROSE

11

Amateur Radio X.25 PLP.

PF_DECnet

12

Reserved for DECnet project.

PF_NETBEUI

13

Reserved for 802.2LLC project.

PF_SECURITY

14

Security callback pseudo AF.

PF_KEY

15

PF_KEY key management API.

PF_NETLINK

16

 

PF_ROUTE

PF_NETLINK

Alias to emulate 4.4BSD.

PF_PACKET

17

Packet family.

PF_ASH

18

Ash.

PF_ECONET

19

Acorn Econet.

PF_ATMSVC

20

ATM SVCs.

PF_SNA

22

Linux SNA Project

PF_IRDA

23

IRDA sockets.

PF_PPPOX

24

PPPoX sockets.

PF_MAX

32

For now.

Note that most of the socket-based calls only work with a limited subset of address/protocol families. The socketpair call is only implemented for the PF_LOCAL (PF_UNIX) family, thus restricting it to same-host communications.

The second argument for the socketpair call, type , indicates the socket type. The defined constant SOCK_STREAM can be used to indicate a stream socket or the defined constant SOCK_DGRAM to indicate a datagram-based socket. The third argument, protocol , is used to indicate the protocol within the specified family. In most cases, this argument is set to 0, which indicates to the system that it should select the protocol. With Internet domain communications, the system will use, by default, UDP for connectionless sockets and TCP for connection-oriented sockets. If necessary, the IPPROTO_TCP or IPPROTO_UDP constants found in the header file can be used to directly select the protocol within a specific family. The fourth argument, sv , is the base address of an integer array that references the two socket descriptors that are created if the call is successful. Each descriptor is bidirectional and is available for both reading and writing. If the socketpair call fails, it returns a -1 and sets errno . The value errno may take, and an interpretation of each value, is shown in Table 10.3.

Table 10.3. socketpair Error Messages.

#

Constant

perror Message

Explanation

14

EFAULT

Bad address

sv references an illegal address.

24

EMFILE

Too many open files

This process has reached the limit for open file descriptors.

93

EPROTONOSUPPORT

Protocol not supported

Requested protocol not supported on this system.

95

EOPNOTSUPPORT

Operation not supported

Specified protocol does not support socket pairs.

97

EAFNOSUPPORT

Address family not supported by protocol

Cannot use the indicated address family with specified protocol family.

Program 10.1 creates a socket pair, forks a child process, and uses the created sockets to communicate information between the parent and child processes.

Program 10.1 Creating and using a socket pair.

File : p10.1.cxx /* Creating a socket pair */ #include + #include #include #include using namespace std; const int BUF_SZ = 10; 10 int main( ) { int sock[2], // The socket pair i; static char buf[BUF_SZ]; // Temporary buffer for message + if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, sock) < 0) { perror("Generation error"); return 1; } switch (fork( )) { 20 case -1: perror("Bad fork"); return 2; case 0: // The child process close(sock[1]); + for (i = 0; i < 10; i += 2) { sleep(1); sprintf(buf, "c: %d", i); write(sock[0], buf, sizeof(buf)); read( sock[0], buf, BUF_SZ); 30 cout << "c-> " << buf << endl; // Message from parent } close(sock[0]); break; default: // The parent process + close(sock[0]); for (i = 1; i < 10; i += 2) { sleep(1); read( sock[1], buf, BUF_SZ); cout << "p-> " << buf << endl; // Message from child 40 sprintf(buf, "p: %d", i); write(sock[1], buf, sizeof(buf)); } close(sock[1]); } + return 0; }

The program starts by creating, with a single call in line 15, a pair of local UNIX datagram sockets. The program then forks, producing a child process. When in the child, the program closes the socket descriptor referenced as sock[1] . It then enters a loop, from 0 to 9, counting in steps of 2, where it does the following. The process sleeps for one second to slow down its output display sequence. It then creates, in a temporary buffer, a message to be sent to the parent process. The message contains the character sequence c: , to label it as from the child, followed by the current integer loop counter value. The contents of the temporary buffer are then written to socket descriptor 0 (sock[0]) using the write system call. Following the write to the socket, the child process reads from the same socket descriptor to obtain the message generated by the parent process. The child process then displays the message from the parent on the screen.

The parent process follows a similar set of steps. However, it closes sock[0] and does its socket reading and writing from sock[1] . When this program is run, it will produce the output as shown in Figure 10.4.

Figure 10.4 The output of Program 10.1.

linux$ p10.1 p-> c: 0 c-> p: 1 p-> c: 2 c-> p: 3 p-> c: 4 c-> p: 5 p-> c: 6 c-> p: 7 p-> c: 8 c-> p: 9

Before the process forks, both sock[0] and sock[1] descriptors are available in the parent for reading and writing. After the fork, the child process closes sock[1] and reads and writes using sock[0] . The parent process closes sock[0] and reads and writes using sock[1] . At the kernel level the sockets are still one and the same. Thus, what the child process writes to sock[0] can be read by the parent process from sock[1] and vice versa. Figure 10.5 presents a diagrammatic representation of this relationship.

Figure 10.5. The socketpair before and after the process forks.

EXERCISE

What happens when you adjust the sleep times in the child/parent processes in Program 10.1? Will the parent/child processes wait for each other no matter what the time differential? Why? Why not? Now edit the p10.1.cxx file and change both sleep times to 3 seconds. Recompile the source as p10.1 . Read the manual page on netstat . Issue the following command sequence:

linux$ p10.1 & netstat -p -x grep p10.1

What information is returned by the netstat command? Once the p10.1 program is finished reissue just the netstat command with the -p -x options . What does this tell you about what the system is doing?

Категории