第3章 关于名称和地址族
There are a number of ways to resolve names into binary quantities; your system probably provides access to several of these. Some of them involve interaction with other systems “under the covers”; others are strictly local.
It is critical to remember that a name service is not required for TCP/IP to work.
Accessing the Name Service
int getaddrinfo (const char *hostStr, const char *serviceStr, const struct addrinfo *hints, struct addrinfo **results)
The first two arguments to getaddrinfo() point to null-terminated character strings representing a host name or address and a service name or port number, respectively.
The third argument describes the kind of information to be returned.
results 是struct addrinfo指针的位置,将存储一个指向包含结果的链表的指针。
成功返回0,失败返回非0错误代码
另外两个辅助函数
void freeaddrinfo(struct addrinfo *addrList)
释放getaddrinfo()返回的列表内存。
const char *gai_strerror(int errorCode)
传递一个错误代码,返回描述错误的字符串。
struct addrinfo {
int ai_flags; // Flags to control info resolution
int ai_family; // Family: AF_INET, AF_INET6, AF_UNSPEC
int ai_socktype; // Socket type: SOCK_STREAM, SOCK_DGRAM
int ai_protocol; // Protocol: 0 (default) or IPPROTO_XXX
socklen_t ai_addrlen; // Length of socket address ai_addr
struct sockaddr *ai_addr; // Socket address for socket
char *ai_canonname; // Canonical name
struct addrinfo *ai_next; // Next addrinfo in linked list
};
For systems that support both IPv4 and IPv6, IPv6 will generally be returned first by getaddrinfo() because it offers more options for interoperability.
IPv4–IPv6 Interoperation
Our generic client and server are oblivious to whether they are using IPv4 or IPv6 sockets. An obvious question is, “What if one is using IPv4 and the other IPv6?” The answer is that if (and only if) the program using IPv6 is a dual-stack system—that is, supports both verson 4 and version 6—they should be able to interoperate. The existence of the special “v4-to-v6-mapped” address class makes this possible. This mechanism allows an IPv6 socket to be connected to an IPv4 socket. A full discussion of the implications of this and how it works is beyond the scope of this book, but the basic idea is that the IPv6 implementation in a dual-stack system recognizes that communication is desired between an IPv4 address and an IPv6 socket, and translates the IPv4 address into a “v4-to-v6-mapped” address. Thus, each socket deals with an address in its own format.
For example, if the client is a v4 socket with address 1.2.3.4, and the server is listening on a v6 socket in a dual-stack platform, when the connection request comes in, the server-side implementation will automatically do the conversion and tell the server that it is connected to a v6 socket with the v4-mapped address ::ffff:1.2.3.4. (Note that there is a bit more to it than this; in particular, the server side implementation will first try to match to a socket bound to a v4 address, and do the conversion only if it fails to find a match; see Chapter 7 for more details.)
If the server is listening on a v4 socket, the client is trying to connect from a v6 socket on a dual-stack platform, and the client has not bound the socket to a particular address before calling connect(), the client-side implementation will recognize that it is connecting to an IPv4 address and assign a v4-mapped IPv6 address to the socket at connect() time. The stack will “magically” convert the assigned address to an IPv4 address when the connection request is sent out. Note that, in both cases, the message that goes over the network is actually an IPv4 message.
Getting Names from Numbers
int getnameinfo (const struct sockaddr *address, socklen_t addressLength, char *node, socklen_t nodeLength, char * service, socklen_t serviceLength, int flags)
返回0表示成功,非0表示失败
int gethostname(char *nameBuffer, size_t bufferLength)