Socket pair, also known as socket pipeline, is mainly used to implement one-to-one full or half-duplex communication within or between processes. It is used in IO reuse models (such as select, poll, epoll, etc) it plays a role in notifying the interruption and exit loop. There are already ready-made implementations in UNIX-like systems. The API is socketpair, but it is not in WINDOWS, therefore, this article mainly describes the implementation of soketpair on the WINDOWS platform, and supports tcp and udp socket pipelines under IPv4 and IPv6. The implementation principle of tcp is that one end listens to the connection from the other end on the retrieval address and a port, while the implementation principle of udp is to bind the retrieval address and a port on both ends, then set the peer address (call connect implementation ). The bound loopback addresses are 127.0.0.1 and 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 1, respectively, and the ports are allocated by the system.
Interface
1 # ifdef _ cplusplus
2 extern "C "{
3 # endif
4
5 # ifdef WIN32
6 # include <winsock2.h>
7 # pragma comment (lib, "ws2_32.lib ")
8 # endif
9
10 # ifdef WIN32
11 # define socket_t SOCKET
12 # else
13 # define socket_t int
14 # endif
15
16 int socket_pair (int family, int type, int protocol, socket_t sock [2]);
17
18 # ifdef _ cplusplus
19}
20 # endif
Implementation
1 # ifdef WIN32
2 # include <ws2tcpip. h>
3
4 static int _ stream_socketpair (struct addrinfo * ai, socket_t sock [2])
5 {
6 SOCKET listener, client = INVALID_SOCKET, server = INVALID_SOCKET;
7 int opt = 1;
8
9 listener = socket (ai-> ai_family, ai-> ai_socktype, ai-> ai_protocol );
10 if (INVALID_SOCKET = listener)
11 goto fail;
12
13 setsockopt (listener, SOL_SOCKET, SO_REUSEADDR, (const char *) & opt, sizeof (opt ));
14
15 if (SOCKET_ERROR = bind (listener, ai-> ai_addr, ai-> ai_addrlen ))
16 goto fail;
17
18 if (SOCKET_ERROR = getsockname (listener, ai-> ai_addr, (int *) & ai-> ai_addrlen ))
19 goto fail;
20
21 if (SOCKET_ERROR = listen (listener, SOMAXCONN ))
22 goto fail;
23
24 client = socket (ai-> ai_family, ai-> ai_socktype, ai-> ai_protocol );
25 if (INVALID_SOCKET = client)
26 goto fail;
27
28 if (SOCKET_ERROR = connect (client, ai-> ai_addr, ai-> ai_addrlen ))
29 goto fail;
30
31 server = accept (listener, 0, 0 );
32 if (INVALID_SOCKET = server)
33 goto fail;
34
35 closesocket (listener );
36 sock [0] = client, sock [1] = server;
37 return 0;
38
39 fail:
40 if (INVALID_SOCKET! = Listener)
41 closesocket (listener );
42 if (INVALID_SOCKET! = Client)
43 closesocket (client );
44 return-1;
45}
46
47 static int _ dgram_socketpair (struct addrinfo * ai, SOCKET sock [2])
48 {
49 SOCKET client = INVALID_SOCKET, server = INVALID_SOCKET;
50 struct addrinfo addr, * res = NULL;
51 const char * address;
52 int opt = 1;
53
54 server = socket (ai-> ai_family, ai-> ai_socktype, ai-> ai_protocol );
55 if (INVALID_SOCKET = server)
56 goto fail;
57
58 setsockopt (server, SOL_SOCKET, SO_REUSEADDR, (const char *) & opt, sizeof (opt ));
59
60 if (SOCKET_ERROR = bind (server, ai-> ai_addr, ai-> ai_addrlen ))
61 goto fail;
62
63 if (SOCKET_ERROR = getsockname (server, ai-> ai_addr, (int *) & ai-> ai_addrlen ))
64 goto fail;
65
66 client = socket (ai-> ai_family, ai-> ai_socktype, ai-> ai_protocol );
67 if (INVALID_SOCKET = client)
68 goto fail;
69
70 memset (& addr, 0, sizeof (addr ));
71 addr. ai_family = ai-> ai_family;
72 addr. ai_socktype = ai-> ai_socktype;
73 addr. ai_protocol = ai-> ai_protocol;
74
75 if (AF_INET6 = addr. ai_family)
76 address = "0: 0: 0: 0: 0: 0: 0: 1 ";
77 else
78 address = "127.0.0.1 ";
79
80 if (getaddrinfo (address, "0", & addr, & res ))
81 goto fail;
82
83 setsockopt (client, SOL_SOCKET, SO_REUSEADDR, (const char *) & opt, sizeof (opt ));
84 if (SOCKET_ERROR = bind (client, res-> ai_addr, res-> ai_addrlen ))
85 goto fail;
86
87 if (SOCKET_ERROR = getsockname (client, res-> ai_addr, (int *) & res-> ai_addrlen ))
88 goto fail;
89
90 if (SOCKET_ERROR = connect (server, res-> ai_addr, res-> ai_addrlen ))
91 goto fail;
92
93 if (SOCKET_ERROR = connect (client, ai-> ai_addr, ai-> ai_addrlen ))
94 goto fail;
95
96 freeaddrinfo (res );
97 sock [0] = client, sock [1] = server;
98 return 0;
99
100 fail:
101 if (INVALID_SOCKET! = Client)
102 closesocket (client );
103 if (INVALID_SOCKET! = Server)
104 closesocket (server );
105 if (res)
106 freeaddrinfo (res );
107 return-1;
108}
109
110 static int win32_socketpair (int family, int type, int protocol, socket_t sock [2])
111 {
112 const char * address;
113 struct addrinfo addr, * ai;
114 int ret =-1;
115
116 memset (& addr, 0, sizeof (addr ));
117 addr. ai_family = family;
118 addr. ai_socktype = type;
119 addr. ai_protocol = protocol;
120
121 if (AF_INET6 = family)
122 address = "0: 0: 0: 0: 0: 0: 0: 1 ";
123 else
124 address = "127.0.0.1 ";
125
126 if (0 = getaddrinfo (address, "0", & addr, & ai ))
127 {
128 if (SOCK_STREAM = type)
129 ret = _ stream_socketpair (ai, sock );
130 else if (SOCK_DGRAM = type)
131 ret = _ dgram_socketpair (ai, sock );
132 freeaddrinfo (ai );
133}
134 return ret;
135}
136 # else
137 # include <sys/socket. h>
138 # endif
139
140int socket_pair (int family, int type, int protocol, socket_t sock [2])
141 {
142 # ifndef WIN32
143 return socketpair (family, type, protocol, sock );
144 # else
145 return win32_socketpair (family, type, protocol, sock );
146 # endif
147}
Example
1 // ipv4 byte stream socket Pipeline
2 ret = socket_pair (AF_INET, SOCK_STREAM, 0, sock );
3 if (-1 = ret) return-1;
4
5 ret = send (sock [0], "ipv4 tcp: hello sock 1 \ n", 24, 0 );
6 ret = recv (sock [1], buf, sizeof (buf), 0 );
7 OutputDebugStringA (buf );
8
9 ret = send (sock [1], "ipv4 tcp: hello sock 0 \ n", 24, 0 );
10 ret = recv (sock [0], buf, sizeof (buf), 0 );
11 OutputDebugStringA (buf );
12
13 // ipv4 datagram socket Pipeline
14 ret = socket_pair (AF_INET, SOCK_DGRAM, 0, sock );
15 if (-1 = ret) return-1;
16
17 ret = send (sock [0], "ipv4 udp: hello sock 1 \ n", 24, 0 );
18 ret = recv (sock [1], buf, sizeof (buf), 0 );
19 OutputDebugStringA (buf );
20
21 ret = sendto (sock [1], "ipv4 udp: hello sock 0 \ n", 24, 0, NULL, 0 );
22 ret = recvfrom (sock [0], buf, sizeof (buf), 0, (struct sockaddr *) & r_addr, & r_len );
23 OutputDebugStringA (buf );
24
25 // ipv6 byte stream socket Pipeline
26 ret = socket_pair (AF_INET6, SOCK_STREAM, IPPROTO_TCP, sock );
27 if (-1 = ret) return-1;
28
29 ret = send (sock [0], "ipv6 tcp: hello sock 1 \ n", 24, 0 );
30 ret = recv (sock [1], buf, sizeof (buf), 0 );
31 OutputDebugStringA (buf );
32
33 ret = send (sock [1], "ipv6 tcp: hello sock 0 \ n", 24, 0 );
34 ret = recv (sock [0], buf, sizeof (buf), 0 );
35 OutputDebugStringA (buf );
36
37 // ipv6 datagram socket Pipeline
38 ret = socket_pair (AF_INET6, SOCK_DGRAM, IPPROTO_UDP, sock );
39 if (-1 = ret) return-1;
40
41 ret = send (sock [0], "ipv6 udp: hello sock 1 \ n", 24, 0 );
42 ret = recv (sock [1], buf, sizeof (buf), 0 );
43 OutputDebugStringA (buf );
44
45 ret = sendto (sock [1], "ipv6 udp: hello sock 0 \ n", 24, 0, NULL, 0 );
46 ret = recvfrom (sock [0], buf, sizeof (buf), 0, NULL, 0 );
47 OutputDebugStringA (buf );
From top to bottom, for connected udp sockets, you can call recv or recvfrom to receive data, call send or sendto to send data, but call sendto to not specify the target address. The test host must support both IPv4 and IPv6 protocols. The output is as follows:
Ipv4 tcp: hello sock 1
Ipv4 tcp: hello sock 0
Ipv4 udp: hello sock 1
Ipv4 udp: hello sock 0
Ipv6 tcp: hello sock 1
Ipv6 tcp: hello sock 0
Ipv6 udp: hello sock 1
Ipv6 udp: hello sock 0
Author: December