作者:陶宁,华清远见嵌入式学院讲师。
在实验过程中,有很多同学经常会问一些函数及该函数的使用方法,下面对网络部分函数进行一次讲解。
1. gethostname 获得主机名
2. getpeername 获得与套接口相连的远程协议地址,用于从端口s中获取与它捆绑的端口名,并把它存放在sockaddr类型的name结构中。它适用于数据报或流类套接口。
3. getsockname 获得套接口本地协议地址,用于获取一个套接口的名字。它用于一个已捆绑或已连接套接口s,本地地址将被返回。本调用特别适用于如下情况:未调用bind()就调用了connect(),这时唯有getsockname()调用可以获知系统内定的本地地址。在返回时,namelen参数包含了名字的实际字节数。
4. gethostbyname 根据根据主机名获得主机信息
5. gethostbyaddr 根据主机地址取得主机协议信息
6. getprotobynumber 根据协议号取得主机协议信息
7. getservbyname 根据服务名取得相关服务信息
8. getservbyport 根据端口号取得相关服务信息
这里很多都是库函数,这些函数都是用来做信息简索的。比如在socket的时候,连接已经建立了,在做accept的时候,不去取对方的IP地址和端口号,以后还是会有机会去取的,也就是说连接还在持续的,我们还是会知道的。
我们先来看下gethostname 这个函数
结果:
Hostname : farsight
通过程序看到,我们的主机获得的服务器主机是farsight
getpeername()
函数原型:
#include <winsock.h>
int PASCAL FAR getpeername( SOCKET s, struct sockaddr FAR* name,
int FAR* namelen);
name:接收端地址的名字结构。
namelen:一个指向名字结构的指针。
例:
getsockname()
函数原型:
#include <winsock.h>
int PASCAL FAR getsockname( SOCKET s, struct sockaddr FAR* name,
int FAR* namelen);
s:标识一个已捆绑套接口的描述字。
name:接收套接口的地址(名字)。
namelen:名字缓冲区长度。
getsockname()函数用于获取一个套接口的名字。它用于一个已捆绑或已连接套接口s,本地地址将被返回。本调用特别适用于如下情况:未调用bind()就调用了connect(),这时唯有getsockname()调用可以获知系统内定的本地地址。在返回时,namelen参数包含了名字的实际字节数。
gethostbyaddr()
#include <winsock.h>
struct hostent FAR *PASCAL FAR gethostbyaddr(const char
FAR * addr, int len, int type);
addr:指向网络字节顺序地址的指针。
len: 地址的长度,在PF_INET类型地址中为4。
type:地址类型,应为PF_INET。
gethostbyaddr()返回对应于给定地址的包含主机名字和地址信息的hostent结构指针。结构的声明如下:
struct hostent {
char FAR * h_name;
char FAR * FAR * h_aliases;
short h_addrtype;
short h_length;
char FAR * FAR * h_addr_list;
};
结果:
getprotobynumber()
#include <winsock.h>
struct protoent FAR * PASCAL FAR getprotobynumber(int number);
number:一个以主机顺序排列的协议号。
返回的指针指向一个由Windows Sockets实现分配的结构。应用程序不应该试图修改这个结构或者释放它的任何部分。此外,每一线程仅有一份这个结构的拷贝,所以应用程序应该在发出其 他Windows Scokets API调用前,把自己所需的信息拷贝下来。
结果:
getservbyname()
#include <windows.h>
struct servent FAR * PASCAL FAR getservbyname(const char
Far * name, const char FAR *proto);
name: 一个指向服务名的指针。
proto: 指向协议名的指针(可选)。如果这个指针为空,getservbyname()返回第一个name与s_name或者某一个s_aliases匹配的服务条目。否则getservbyname()对name和proto都进行匹配。
注释:
getservbyname()返回与给定服务名对应的包含名字和服务号信息的servent结构指针。结构的声明如下:
struct servent {
char FAR * s_name;
char Far * FAR * s_aliases;
short s_port;
char FAR * s_proto;
};
结构的成员有:
成员 用途
s_name 正规的服务名。
s_aliases 一个以空指针结尾的可选服务名队列。
s_port 连接该服务时需要用到的端口号,返回的端口号是以网络字节顺序排列的。
s_proto 连接该服务时用到的协议名。
返回的指针指向一个由Windows Sockets实现分配的结构。应用程序不应该试图修改这个结构或者释放它的任何部分。此外,每一线程仅有一份这个结构的拷贝,所以应用程序应该在发出其 他Windows Scokets API调用前,把自己所需的信息拷贝下来。
例子:
结果:
gethostbyname()
返回对应于给定主机名的主机信息。
#include <winsock2.h>
struct hostent FAR *PASCAL FAR gethostbyname(const char
FAR * name);
name:指向主机名的指针。
注释:
gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针。结构的声明与gethostaddr()中一致。
返回的指针指向一个由Windows Sockets实现分配的结构。应用程序不应该试图修改这个结构或者释放它的任何部分。此外,每一线程仅有一份这个结构的拷贝,所以应用程序应该在发出其 他Windows Scokets API调用前,把自己所需的信息拷贝下来。
gethostbyname()实现没有必要识别传送给它的IP地址串。对于这样的请求,应该把IP地址串当作一个未知主机名同样处理。如果应用程序有IP地址串需要处理,它应该使用inet_addr()函数把地址串转换为IP地址,然后调用gethostbyaddr()来得到hostent结构。
接着来看下主要的gethosbytname 做域名解析的这块,
大家先来看下nslookup
查看配置文件cat /etc/resolv.conf
cat /etc/nsswitch.conf 这个文件,这个文件是对主机进行配置,此配置的获得高于host文件,目的是比如:有些域名是假的,你解析不出来的,可以做一个自己的对应,或者说有一些坏人,在你的host文件中把一些网站如:google baidu改成自己的网站,因为系统在检查这个文件是高于rcsserver的。
下面来看一下 Nslookup 的debug 会让我们返回更多信息来。
如:www.google.com的信息
-----------------------------------------------------
QUESTIONS: //这里面就是我们所问的问题:
www.google.com, type = A, class = IN //查询 www.google.com 的A 类型的地址,A类型是地址(dns中)
ANSWERS:
-> www.google.com
canonical name = www.l.google.com.
-> www.l.google.com
internet address = 64.233.189.147
-> www.l.google.com
internet address = 64.233.189.99
-> www.l.google.com
internet address = 64.233.189.103
-> www.l.google.com
internet address = 64.233.189.104
AUTHORITY RECORDS:
-> google.com
nameserver = ns2.google.com.
-> google.com
nameserver = ns3.google.com.
-> google.com
nameserver = ns4.google.com.
-> google.com
nameserver = ns1.google.com.
ADDITIONAL RECORDS:
-> ns1.google.com
internet address = 216.239.32.10
-> ns2.google.com
internet address = 216.239.34.10
-> ns3.google.com
internet address = 216.239.36.10
-> ns4.google.com
internet address = 216.239.38.10
---------------------------------------------------------
也可以让type=mx
如
注意:权值为10的,如果有权值为20的,则会先查权值为10的。
我们再通过发发邮件过程来看过程:
1、 查DNS 查mx 记录 会返回一组数,
2、 返回优先级高的,发的时候也是优先级高的,返回的时候也会是优先级别高的。
3、 收发都是用SMTP协议。
也就是说我们的邮件会通过smtp协议一站一站的传递下去。
注意IP地址也可以回到域名,也就是我们所说的反向域名解析。
例如:有的时候我们访问一个服务器,速度会比较慢,那么他有可能在反向域名解析呢。
讲了这么多相关的,我们看下函数原型把:
#include <netdb.h>
#include <sys/socket.h>
struct hostent *gethostbyname(const char *name);
这个函数的传入值是域名或者主机名,例如"www.google.com"等等。
传出值,是一个hostent的结构(如下)。如果函数调用失败,将返回NULL。
struct hostent {
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
};
Gethostbyname 它会返回一个结构体,也就是说我们给定一个结构体,返回的名字是hostent ,这个名字可以是一个主机名称,同时也可以是一个IPV4地址(域名解析),也就是说我们也可以对一个IP做解析,现在是也可以的,但是在早期的时候是不行的,早期的时候域名解析就是解析域名,早期的时候我们用gethostbyaddr ,现在来说,我们用gethostbyname和早期的gethostbyname + gethostbyaddr. 是同样道理了,呵呵。