获取主机信息,网络信息AIP,getsockname,getpeername,getservbyname,getservbyport,inet_ntop,inet_pton
获取主机信息
1.ip地址转换,主机字节序 <---> 网络字节序
#include <arpa/inet.h> int inet_pton(int af, const char* src, void* dst); const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt)
inet_pton函数将用字符串表示的IP地址src(用淀粉十进制字符串表示的IPv4地址或用十六进制字符串表示的IPv6地址)转换成用网络字节序整数表示的IP地址,并把转换结果存储于dst指向的内存中。
其中,af 参数指定地址族,可以使AF_INET或者AF_INET6.inet_pton成功时返回1,失败时返回0,病设置errno。
inet_ntop函数进行相反的转换,前3个参数含义与inet_pton的参数相同,最后一个参数cnt指定目标存储单元的大小。成功时返回目标存储单元的地址,失败则返回NULL并设置errno。
这个头文件里面定义了“目标存储单元的大小”
#include <netinet/in.h> #define INET_ADDRESSLEN 16 #define INET6_ADDRESSLEN 46
2.地址信息函数:
#include <sys/socket.h> int getsockname(int sockfd, struct sockaddr* address, socklen_t* address_len); int getpeername(int sockfd, struct slckaddr* address, socklen_t* address_len);
getsockanme获取sockfd对应的本端socket地址,并将其存储于address参数指定的内存中,该socket地址的长度则存储于address_len参数指向的变量中。如果实际socket地址的长度大于address所指内存区的大小,那么该socket地址将被截断。getsocketname成功时返回0,失败则返回-1,并设置errno。
getpeername获取sockfd对应的远端socket地址,其参数及返回值的含义与getsockname的参数及返回值相同。
3.网络信息AIP
#include <netdb.h> struct hostent* gethostbyname(const char* name); struct hostent* gethostbyaddr(const void* addr, size_t len, int type); struct hostent { char* h_name; char** h_aliases; int h_addrtype; int h_length; char** h_addr_list;//按网络字节序列出的主机IP地址列表 };
gethostbyname 函数根据主机名称获取主机的完整信息,
gethostbyaddr函数根据IP地址获取主机的完整信息。
gethostbyname函数通常先在本地的 /etc/hsots配置的文件中查找主机,
如果没有找到,再去访问DNS服务器。
#include <netdb.h> struct servent* getservbyname(const char* name, const char* proto); struct servent* getsrvbyport(int port, const char* proto); struct servent { char* s_name; char** s_aliases; int s_port; char* s_proto; };
getservbyname函数根据名称获取某个服务的完整信息,
getsrvbyport函数根据端口号获取某个服务的完整信息。
他们实际上都是通过读取 /etc/services 文件来获取服务信息的
#include <netdb.h> int getaddrinfo(const char* hostname, const char* service, const struct addrinfo* hints, struct addrinfo** result) struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklent_t ai_addrlen; char* ai_canonname; struct sockaddr* ai_addr; struct addrinfo* ai_next; };
getaddrinfo函数既能通过主机名获取ip地址也能通过服务名获得端口号。
#include <netdb.h> int getnameinfo(const struct sockaddr* sockaddr, socklen_t addrlen, char* host, socklen_t hostlen, char* serv, socklen_t servlen, int flags);
getnameinfo函数能通过socket地址同时获得以字符串表示的主机名和服务名。
4.举例说明:
举个例子A:
const char* ip = argv[1]; int port = atoi(argv[2]); int backlog = atoi(argv[3]); int sock = socket(PF_INET, SOCK_STREAM, 0); assert(socket >= 0); // create a ipv4 socket address struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family = AF_INET; inet_pton(AF_INET, ip, &address.sin_addr); address.sin_port = htons(port);
举个例子B:
if(connect(sock, (struct sockaddr*)&serverSocket, sizeof(serverSocket)) != -1) { char buffer[BUFFER_SIZE]; memset(buffer, '\0', sizeof(buffer)); send(sock, buffer, BUFFER_SIZE, 0); //client get server(peer) name struct sockaddr_in peerHost; socklen_t client_addrlength = sizeof(peerHost); getpeername(sock, (struct sockaddr*)&peerHost, &client_addrlength ); char dest[100] ; inet_ntop(AF_INET, &peerHost.sin_addr,dest,100); int peerPort=ntohs(peerHost.sin_port); printf("dest ip : %s, port:%d", dest, peerPort); }
举个例子C:(完整版. 客户端)
#include <sys/socket.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #define BUFFER_SIZE 512 int main(int argc, char* argv[]) { if(argc<=2) { printf("usage: %s ip_address, port_number send_buffer_size \r\n", basename(argv[0])); return 1; } char* ip = argv[1]; int port = atoi(argv[2]); struct sockaddr_in serverSocket; bzero(&serverSocket, sizeof(serverSocket)); serverSocket.sin_port = htons(port); serverSocket.sin_family = AF_INET; inet_pton(AF_INET, ip , &serverSocket.sin_addr); int sock = socket(PF_INET, SOCK_STREAM, 0); assert(sock>=0); int sendBuf =atoi(argv[3]); int len = sizeof(sendBuf); //set tcp buff ,and read setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendBuf, sizeof(sendBuf)); getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendBuf, (socklen_t*)&len); printf("the tcp send buffer size after setting is %d.\r\n", sendBuf); if(connect(sock, (struct sockaddr*)&serverSocket, sizeof(serverSocket)) != -1) { char buffer[BUFFER_SIZE]; memset(buffer, '\0', sizeof(buffer)); send(sock, buffer, BUFFER_SIZE, 0); //client get server(peer) name struct sockaddr_in peerHost; socklen_t client_addrlength = sizeof(peerHost); getpeername(sock, (struct sockaddr*)&peerHost, &client_addrlength ); char dest[100] ; inet_ntop(AF_INET, &peerHost.sin_addr,dest,100); int peerPort=ntohs(peerHost.sin_port); printf("dest ip : %s, port:%d", dest, peerPort); } close(sock); return 0; }
举个例子D:完整版(服务器)
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <string.h> #define BUFFER_SIZE 1024 int main(int argc, char* argv[]) { if(argc<=2) { printf("suage:%s IP_number port_number recv_buffer.\r\n", basename(argv[0])); return 1; } char* ip = argv[1]; int port = atoi(argv[2]); struct sockaddr_in serverAddr; bzero(&serverAddr,sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(port); inet_pton(AF_INET,ip, &serverAddr.sin_addr); int sockfd = socket(PF_INET, SOCK_STREAM,0); assert(sockfd>=0); int recvbuf = atoi(argv[3]); int len = sizeof(recvbuf); //set tcp bufsize,then read it. setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recvbuf, sizeof(recvbuf)); getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recvbuf, (socklen_t*)&len); printf("The tcp receive buffer size after setting is %d.\r\n", recvbuf); int ret = bind(sockfd, (struct sockaddr*)&serverAddr,sizeof(serverAddr)); assert(ret>=0); ret = listen(sockfd, 5); assert(ret>=0); struct sockaddr_in client; socklen_t client_addrlength = sizeof(client); int connfd = accept(sockfd, (struct sockaddr*)&client, &client_addrlength); if(connfd < 0) { printf("errno is:%d \r\n", errno); } else { char buffer[BUFFER_SIZE]; memset(buffer,'\0', sizeof(buffer)); while(recv(connfd, buffer, BUFFER_SIZE-1, 0) > 0) { printf("recv success..."); } close(connfd); } close(sockfd); return 0; }
举个例子E:完整版(访问某个开启了daytime的主机)
#include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <assert.h> int main(int argc, char* argv[]) { assert(argc ==2); char* host = argv[1]; //get dest host ip info struct hostent* hostinfo = gethostbyname(host); assert(hostinfo); //get daytime info struct servent* servinfo = getservbyname("daytime", "tcp"); assert(servinfo); //// attention the struct convert struct in_addr pNetIp = *(struct in_addr*)*hostinfo->h_addr_list; char serverHostIp[100] ; inet_ntop(AF_INET, &pNetIp, serverHostIp, 100); printf("server host ip:[%s].daytime port is %d.\r\n",serverHostIp, ntohs(servinfo->s_port)); struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family = AF_INET; address.sin_port = servinfo->s_port; // Attention! directly use servent address.sin_addr = *(struct in_addr*)*hostinfo->h_addr_list; int sockfd = socket(AF_INET, SOCK_STREAM, 0); int result = connect(sockfd, (struct sockaddr*)&address, sizeof(address)); assert(result != -1); char buffer[128]; result = read(sockfd, buffer, sizeof(buffer)); assert(result > 0); buffer[result] = '\0'; printf("the day time is: %s", buffer); close(sockfd); return 0; }