Preface :
In this section, we'll cover how to develop applications that work seamlessly over IPv4 and IPv6. This method requires using the new name resolution APIs getaddrinfo and getnameinfo and requires a bit of rearranging Winsock calls from what you are probably used to.
Before we get into the specifics, let's cover some of the basic practices that you should follow. First, applications should not allocate the socket address structures specific to each protocol (such as SOCKADDR_IN and SOCKADDR_IN6 for IPv4 and IPv6, respectively) because they can be different sizes. Instead, a new socket address structure SOCKADDR_STORAGE has been introduced that is as large as the largest possible protocol specific address structure and includes padding for 64-bit alignment issues. The following code uses a SOCKADDR_STORAGE structure to store the destination IPv6 address :
Second, functions that take an address as a parameter should pass the entire socket address structure and not the protocol specific types like struct in_addror struct in6_addr. This is important for IPv6, which might require the scope ID information to successfully connect. The SOCKADDR_STORAGE structure containing the address should be passed instead.
Third, avoid hardcode addresses regardless of whether they are IPv4 or IPv6. The Winsock header files define constants for all the address that are hard coded such as the loopback address and the wildcard address used for binding.
Now that some of the basic issues are out of the way, let's move to discussing how an application should be structured to be IP independent. We will divide our discussion into two sections: the client and the server.
Client :
For both TCP and UDP clients, the application typically possesses the server (or recipient's) IP address or hostname. Whether it resolves to an IPv4 address or IPv6 address doesn't matter. The client should follow these three steps :
The following code sample illustrates these principles :
First, you will notice that there are no explicit references to AF_INET or AF_INET6. Also, there's no need to manipulate the underlying SOCKADDR_IN orSOCKADDR_IN6 addresses. The getaddrinfo call fully initializes the returned socket address structure with all the required information—address family, binary address, etc.—that is necessary for connecting or sending datagrams.
If the client application needs to explicitly bind the socket to a local port after socket creation but before connect or sendto, then another getaddrinfo call can be made. This call would specify the address family, socket type, and protocol returned from the first call along with the AI_PASSIVE flag and desired local port, which will return another socket address structure initialized to the necessary bind address (such as 0.0.0.0 for IPv4 and :: for IPv6).
Server :
The server side is a bit more involved than the client side. This is because the Windows IPv6 stack is a dual stack. That is, there is a separate stack for IPv4 and IPv6, so if a server wishes to accept both IPv4 and IPv6 connections, it must create a socket for each one. The two steps for creating an IP independent server are the following :
The following code illustrates this principle :
Once the sockets are created and bound, the application simply needs to wait for incoming connections on each. Chapter 5 covers the various I/O models available in Winsock and provides fully functioning client and server samples that are written using the principles covered in this section.
In this section, we'll cover how to develop applications that work seamlessly over IPv4 and IPv6. This method requires using the new name resolution APIs getaddrinfo and getnameinfo and requires a bit of rearranging Winsock calls from what you are probably used to.
Before we get into the specifics, let's cover some of the basic practices that you should follow. First, applications should not allocate the socket address structures specific to each protocol (such as SOCKADDR_IN and SOCKADDR_IN6 for IPv4 and IPv6, respectively) because they can be different sizes. Instead, a new socket address structure SOCKADDR_STORAGE has been introduced that is as large as the largest possible protocol specific address structure and includes padding for 64-bit alignment issues. The following code uses a SOCKADDR_STORAGE structure to store the destination IPv6 address :
- SOCKADDR_STORAGE saDestination;
- SOCKET s;
- int addrlen,
- rc;
- s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
- if (s == INVALID_SOCKET) {
- // socket failed
- }
- addrlen = sizeof(saDestination);
- rc = WSAStringToAddress(
- "3ffe:2900:d005:f28d:250:8bff:fea0:92ed",
- AF_INET6,
- NULL,
- (SOCKADDR *)&saDestination,
- &addrlen
- );
- if (rc == SOCKET_ERROR) {
- // conversion failed
- }
- rc = connect(s, (SOCKADDR *)&saDestination, sizeof(saDestination));
- if (rc == SOCKET_ERROR) {
- // connect failed
- }
Third, avoid hardcode addresses regardless of whether they are IPv4 or IPv6. The Winsock header files define constants for all the address that are hard coded such as the loopback address and the wildcard address used for binding.
Now that some of the basic issues are out of the way, let's move to discussing how an application should be structured to be IP independent. We will divide our discussion into two sections: the client and the server.
Client :
For both TCP and UDP clients, the application typically possesses the server (or recipient's) IP address or hostname. Whether it resolves to an IPv4 address or IPv6 address doesn't matter. The client should follow these three steps :
The following code sample illustrates these principles :
- SOCKET s;
- struct addrinfo hints,
- *res=NULL
- char *szRemoteAddress=NULL,
- *szRemotePort=NULL;
- int rc;
- // Parse the command line to obtain the remote server's
- // hostname or address along with the port number, which are contained
- // in szRemoteAddress and szRemotePort.
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- // first resolve assuming string is a string literal address
- rc = getaddrinfo(
- szRemoteAddress,
- szRemotePort,
- &hints,
- &res
- );
- if (rc == WSANO_DATA) {
- // Unable to resolve name - bail out
- }
- s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (s == INVALID_SOCKET) {
- // socket failed
- }
- rc = connect(s, res->ai_addr, res->ai_addrlen);
- if (rc == SOCKET_ERROR) {
- // connect failed
- }
- freeaddrinfo(res);
If the client application needs to explicitly bind the socket to a local port after socket creation but before connect or sendto, then another getaddrinfo call can be made. This call would specify the address family, socket type, and protocol returned from the first call along with the AI_PASSIVE flag and desired local port, which will return another socket address structure initialized to the necessary bind address (such as 0.0.0.0 for IPv4 and :: for IPv6).
Server :
The server side is a bit more involved than the client side. This is because the Windows IPv6 stack is a dual stack. That is, there is a separate stack for IPv4 and IPv6, so if a server wishes to accept both IPv4 and IPv6 connections, it must create a socket for each one. The two steps for creating an IP independent server are the following :
The following code illustrates this principle :
- SOCKET slisten[16];
- char *szPort="5150";
- struct addrinfo hints,
- * res=NULL,
- * ptr=NULL;
- int count=0,
- rc;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_flags = AI_PASSIVE;
- rc = getaddrinfo(NULL, szPort, &hints, &res);
- if (rc != 0) {
- // failed for some reason
- }
- ptr = res;
- while (ptr)
- {
- slisten[count] = socket(ptr->ai_family,
- ptr->ai_socktype, ptr->ai_protocol);
- if (slisten[count] == INVALID_SOCKET) {
- // socket failed
- }
- rc = bind(slisten[count], ptr->ai_addr, ptr->ai_addrlen);
- if (rc == SOCKET_ERROR) {
- // bind failed
- }
- rc = listen(slisten[count], 7);
- if (rc == SOCKET_ERROR) {
- // listen failed
- }
- count++;
- ptr = ptr->ai_next;
- }
This message was edited 4 times. Last update was at 16/04/2011 15:55:25
沒有留言:
張貼留言