网络信息相关函数
gethostbyname和gethostbyaddr
gethostbyname根據主機名稱獲取主機的完整信息,gethostbyaddr根據IP地址獲取主機的完整信息。
gethostname通常先在本地/etc/hosts配置文件查找,如果沒有再向DNS服務器查找。
#include <unistd.h> #include <sys/socket.h>int gethostname(char *name, size_t len);struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type); struct hostent {char *h_name; /* 主機名 */char **h_aliases; /* 主機別名列表 */int h_addrtype; /* 地址類型 */int h_length; /* 地址長度 */char **h_addr_list; /* ip地址列表 */ }name參數指定目標主機名,addr參數指定目標主機的IP地址,len參數指定addr的地址大小,type參數指定addr所指IP地址的類型。
代碼實現:根據主機名baidu和百度的ip地址獲取百度的信息。
getservbyname和getservbyport
#include <netdb.h>struct servent *getservent(void); struct servent *getservbyname(const char *name, const char *proto); struct servent *getservbyport(int port, const char *proto);getservbyname函數根據名稱獲取某個服務的完整信息。
getservbyport函數根據端口號獲取某個服務的完整信息。
name參數指定服務名字。
port參數指定目標服務對應的端口號。
proto參數指定服務類型。
函數返回的都是servent指針,結構體servent定義如下:
struct servent {char *s_name; /* 服務名稱 */char **s_aliases; /* 服務別名列表 */int s_port; /* 端口號 */char *s_proto; /* 服務類型 */ }代碼:編寫一個程序,使用主機名和服務名訪問目標服務器上的daytime服務,獲取該機器的系統時間。
#include <iostream> #include <netdb.h> #include <unistd.h> #include <assert.h> #include <cstring> using namespace std;int main(int argc, char* argv[]) {/* 主函數需要1個參數 */assert(argc == 2);char* host = argv[1];/* 獲取目標主機的地址信息 */hostent* hostinfo = gethostbyname(host);assert(hostinfo);/* 獲取daytime服務信息 */servent* servinfo = getservbyname("daytime", "tcp");assert(servinfo);printf("daytime port is %d\n", servinfo->s_port);/* 創建socket地址 */sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = servinfo->s_port;addr.sin_addr = *(in_addr*)*hostinfo->h_addr_list;/* 創建socket文件描述符 */int sockfd = socket(AF_INET, SOCK_STREAM, 0);assert(sockfd >= 0);/* 連接 */int ret = connect(sockfd, (sockaddr*)&addr, sizeof addr);assert(ret != -1);/* 數據讀寫 */char buffer[128];memset(buffer, '\0', sizeof buffer);ret = read(sockfd, buffer, sizeof buffer);assert(ret > 0);printf("the day is: %s\n", buffer);/* 關閉socket */close(sockfd);return 0; }注意上面四個函數是不可重入的,非線程安全,netdb.h給出了可重入版本,在原函數尾部加上_r即可。
./a.out localhost daytime port is 3328 a.out: GetSysTime.cpp:35: int main(int, char**): Assertion `ret != -1' failed. [1] 30605 abort (core dumped) ./a.out localhost失敗在連接這一步,這是因為默認xinetd是關閉daytime的修改配置文件
service daytime {disable = notype = INTERNALid = daytime-streamsocket_type = streamprotocol = tcpuser = rootwait = no }# This is the udp version. service daytime {disable = notype = INTERNALid = daytime-dgramsocket_type = dgramprotocol = udpuser = rootwait = yes }將disable = yes 改成disable = no,上圖所示,并重啟xinetd。
sudo systemctl restart xinetd.service查看是否服務已經啟動
sudo systemctl status xinetd.service ● xinetd.service - LSB: Starts or stops the xinetd daemon.Loaded: loaded (/etc/init.d/xinetd; generated)Active: active (running) since Mon 2021-10-04 02:59:02 PDT; 17s agoDocs: man:systemd-sysv-generator(8)Process: 30709 ExecStart=/etc/init.d/xinetd start (code=exited, status=0/SUCCESS)Tasks: 1 (limit: 2273)Memory: 364.0KCGroup: /system.slice/xinetd.service└─30734 /usr/sbin/xinetd -pidfile /run/xinetd.pid -stayalive -inetd_compat>開啟服務后,再次嘗試:
./a.out localhost daytime port is 3328 the day is: 04 OCT 2021 03:01:07 PDT雖然中間遇到一些小問題,最終還是解決了。
getaddrinfo
#include <netdb.h>int getaddrinfo(const char *node, const char *service,const struct addrinfo *hints,struct addrinfo **res);此函數既能通過主機名獲得IP地址,也能通過服務名獲取端口號。此函數是否可重用取決于內部調用的是gethostbyname和getservbyname函數的可重入版本。
hostname可以接收主機名,也可以表示接收字符串表示的IP地址。
service可以接收服務名,也可以接收端口號。
hints參數三十應用程序給addrinfo的一個提示,以對getaddrinfo的輸出進行更加精準的控制。
使用hints參數的時候,可以設置ai_flags,ai_family,ai_socktype,ai_protocol四個字段,其它字段必須設置為NULL。
getaddrinfo隱士分配內存。調用結束后使用下面函數釋放內存
#include <netdb.h>void freeaddrinfo(struct addrinfo* res);getnameinfo
總結
- 上一篇: GMM-HMM语音识别
- 下一篇: TK域名转向