端口绑定和域名解析
TCP服务器的同一个端口不能够启动、绑定两次;但UDP服务器可以,但客户端连接上以后,信息只能发送给最新绑定的那个服务器端口,相当于端口被重新绑定了。
域名解析函数
struct hostent{
char *h_name; //主机名
char **h_aliases; //别名
int h_addrtype; //协议类型
int h_length; //网络地址大小
char **h_addr_list; //指向网络地址的指针
};
#include <netdb.h>
struct hostent *gethostent(void);
struct hostent* gethostbyname(const char *hostname);
void sethostent(int stayopen);
void endhostent(void);//有get就有end,用于释放内存
查看/etc/hosts文件可以知道本机的IP和域名
利用gethostbyname解析域名
源代码
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <arpa/inet.h>
void out_addr(struct hostent *h)
{
printf("hostname: %s\n", h->h_name);
printf("addrtype: %s\n", h->h_addrtype == AF_INET ? "IPV4":"IPV6");
char ip[16];
memset(ip, 0, sizeof(ip));
inet_ntop(h->h_addrtype, h->h_addr_list[0], ip, sizeof(ip));
int i = 0;
while(h->h_aliases[i] != NULL){
printf("aliases: %s\n", h->h_aliases[i]);
i++;
}
}
int main(int argc, char *argv[])
{
if(argc < 2){
printf("usage: %s host\n", argv[0]);//输入域名,可以是主机名也可以是别名
exit(1);
}
struct hostent *h;
h = gethostbyname(argv[1]);
if(h != NULL){
out_addr(h);
}
else{
printf("no %s exist\n", argv[1]);
}
return 0;
}
利用gethostent解析域名
源代码
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <arpa/inet.h>
void out_addr(struct hostent *h)
{
printf("hostname: %s\n", h->h_name);
printf("addrtype: %s\n", h->h_addrtype == AF_INET ? "IPV4":"IPV6");
char ip[16];
memset(ip, 0, sizeof(ip));
inet_ntop(h->h_addrtype, h->h_addr_list[0], ip, sizeof(ip));
int i = 0;
while(h->h_aliases[i] != NULL){
printf("aliases: %s\n", h->h_aliases[i]);
i++;
}
}
int main(int argc, char *argv[])
{
if(argc < 2){
fprintf(stderr, "usage: %s host\n", argv[0]);//fprintf输出到指定位置,stderr就是指屏幕
exit(1);
}
struct hostent *h;
while((h = gethostent()) != NULL){//通过遍历,获取每一组
if(!strcmp(argv[1], h->h_name)){//查看每一组的主机名是否与输入的一致
out_addr(h);
exit(0);
}
else{
int i = 0;
while(h->h_aliases[i] != NULL){//主机名没有,再遍历别名
if(!strcmp(argv[1], h->h_aliases[i])){
out_addr(h);
exit(0);
}
i++;
}
}
}
endhostent();
printf("no %s exist\n", argv[1]);
return 0;
}
运行结果
把域名解析函数运用到UDP协议的客户端中
修改time_udp_client.c,把从argv[1]直接获取ip地址,改为从命令行中获得域名,然后利用域名解析函数获取IP地址
域名解析函数
int is_host(struct hostent *host, char *name)
{
if(!strcmp(host->h_name, name)) return 1;
int i = 0;
while(host->h_aliases[i] != NULL)
{
if(!strcmp(host->h_aliases[i], name)) return 1;
i++;
}
return 0;
}
unsigned int get_ip_by_name(char *name)
{
unsigned int ip = 0;
struct hostent *host;
while((host = gethostent()) != NULL){
if(is_host(host, name)){
memcpy(&ip, host->h_addr_list[0], 4);//ipv4 32bit = 4 byte
break;
}
}
endhostent();
return ip;
}
在主函数中调用
//inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);//ip 这是先前的代码
//改用从命令行中获得域名,然后利用域名解析函数获取IP地址
unsigned int ip = get_ip_by_name(argv[1]);//可以直接解析成网络字节序的ip
if(ip != 0){
serveraddr.sin_addr.s_addr = ip;
}
else{
inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);
//如果不需要域名解析,直接把输入的主机字节序转换为网络字节序
}
运行结果
总结
https://www.cnblogs.com/maybe2030/p/4781555.html#_label3【计算机网络基础知识总结】
1. 网络:WAN广域网、MAN城域网、LAN 局域网
2. TCP/IP协议:OSI七层协议、TCP/IP五层/四层协议:物理层-数据链路层-网络层-传输层-【会话层-表示层-应用层】
物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器,网关)
数据链路:PPP、FR、HDLC、VLAN、MAC (网桥,交换机)
网络层:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器)
传输层:TCP、UDP、SPX
会话层:NFS、SQL、NETBIOS、RPC
表示层:JPEG、MPEG、ASCII
应用层:FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS
3. TCP/UDP协议网络基础编程