网关IP应该是具有路由功能的设备的IP号,当A电脑(设备)与B电脑(设备)不在同一个网络时,A电脑数据就会被发往网关,这个网关应该是和A电脑在同一个网络,一般是路由器,再经网关转发到下个路由器,再经这个路由器发往下一个网关,路由器的网关就是它自己的IP,因为它具有路由选择功能
路由器有两个大的端口,路由器的LAN端口控制内网IP,LAN端口的IP也是路由器自身的IP,和与它相连的设备的IP在同一个网络号(同网,假定为NET),这个IP也作为该内网的其它设备的网关(假定为C网关),WAN端口控制与外网的接口IP及网关(假定为D网关),NET网络中的数据要发往外网,那么必须要先发到NET网的网关C,再经过C发往D,再由D发往外网的某个网关,D一般也为另一个具有路由功能的设备的IP
交换机工作在7层中的数据链路层,因此它是通过ARP,RARP
交换机相当于多个网桥,Hub集线器相当于多个中继器
端口(PORT)信息是在传输层被封装,IP信息是在网络层被封装,MAC信息是在数据链路层封装
二层交换机具有ARP功能,当然三层交换机肯定有,上层具有下层的功能,下层向上层提供服务,且交换机是通过MAC地址访问计算机或设备
交换机可以增加带宽(其实是共享,只是在一段时间内,看起来有共同下载或上传速度),这是对内而言;而Hub集线器工作在数据链路层,不可,它是独享方式;路由器也能增加带宽(共享,也可以限制某一些网段的IP的速度)
上行速度不要太大
TCP/IP是一组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇。TCP/IP协议簇分为四层,IP位于协议簇的第二层(对应OSI的第三层),TCP位于协议簇的第三层(对应OSI的第四层)。 TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。这4层分别为:
应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。
应用层协议主要包括如下几个:FTP、TELNET、DNS、SMTP、RIP、NFS、HTTP。
传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
互连网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。
IP(Internet Protocol)协议、ICMP(Internet Control Message Protocol) 控制报文协议、ARP(Address Resolution Protocol)地址转换协议、RARP(Reverse ARP)反向地址转换协议。
IP是网络层的核心,通过路由选择将下一条IP封装后交给接口层。IP数据报是无连接服务。
ICMP是网络层的补充,可以回送报文。用来检测网络是否通畅。
Ping命令就是发送ICMP的echo包,通过回送的echo relay进行网络测试。
ARP是正向地址解析协议,通过已知的IP,寻找对应主机的MAC地址。
RARP是反向地址解析协议,通过MAC地址确定IP地址。比如无盘工作站还有DHCP服务。
网络接口层:对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据,二层交换机工作层。
OSI是Open System Interconnection 的缩写,意为开放式系统互联参考模型。
OSI 七层模型称为开放式系统互联参考模型 OSI 七层模型是一种框架性的设计方法 OSI 七层模型通过七个层次化的结构模型使不同的系统不同的网络之间实现可靠的通讯,因此其最主 要的功能使就是帮助不同类型的主机实现数据传输
物理层 : O S I 模型的最低层或第一层,该层包括物理连网媒介,如电缆连线连接器。物理层的协议产生并检测电压以便发送和接收携带数据的信号。在你的桌面P C 上插入网络接口卡,你就建立了计算机连网的基础。换言之,你提供了一个物理层。尽管物理层不提供纠错服务,但它能够设定数据传输速率并监测数据出错率。网络物理问题,如电线断开,将影响物理层。
数据链路层: O S I 模型的第二层,它控制网络层与物理层之间的通信。它的主要功能是如何在不可靠的物理线路上进行数据的可靠传递。为了保证传输,从网络层接收到的数据被分割成特定的可被物理层传输的帧。帧是用来移动数据的结构包,它不仅包括原始数据,还包括发送方和接收方的网络地址以及纠错和控制信息。其中的地址确定了帧将发送到何处,而纠错和控制信息则确保帧无差错到达。 数据链路层的功能独立于网络和它的节点和所采用的物理层类型,它也不关心是否正在运行 Wo r d 、E x c e l 或使用I n t e r n e t 。有一些连接设备,如交换机,由于它们要对帧解码并使用帧信息将数据发送到正确的接收方,所以它们是工作在数据链路层的。 是二层交换机工作层
网络层: O S I 模型的第三层,其主要功能是将网络地址翻译成对应的物理地址,并决定如何将数据从发送方路由到接收方。 网络层通过综合考虑发送优先权、网络拥塞程度、服务质量以及可选路由的花费来决定从一个网络中节点A 到另一个网络中节点B 的最佳路径。由于网络层处理路由,而路由器因为即连接网络各段,并智能指导数据传送,属于网络层。在网络中,“路由”是基于编址方案、使用模式以及可达性来指引数据的发送。
传输层: O S I 模型中最重要的一层。传输协议同时进行流量控制或是基于接收方可接收数据的快慢程度规定适当的发送速率。除此之外,传输层按照网络能处理的最大尺寸将较长的数据包进行强制分割。例如,以太网无法接收大于1 5 0 0 字节的数据包。发送方节点的传输层将数据分割成较小的数据片,同时对每一数据片安排一序列号,以便数据到达接收方节点的传输层时,能以正确的顺序重组。该过程即被称为排序。 工作在传输层的一种服务是 T C P / I P 协议套中的T C P (传输控制协议),另一项传输层服务是I P X / S P X 协议集的S P X (序列包交换)。
会话层: 负责在网络中的两节点之间建立和维持通信。 会话层的功能包括:建立通信链接,保持会话过程通信链接的畅通,同步两个节点之间的对 话,决定通信是否被中断以及通信中断时决定从何处重新发送。 你可能常常听到有人把会话层称作网络通信的“交通警察”。当通过拨号向你的 I S P (因特网服务提供商)请求连接到因特网时,I S P 服务器上的会话层向你与你的P C 客户机上的会话层进行协商连接。若你的电话线偶然从墙上插孔脱落时,你终端机上的会话层将检测到连接中断并重新发起连接。会话层通过决定节点通信的优先级和通信时间的长短来设置通信期限
表示层: 应用程序和网络之间的翻译官,在表示层,数据将按照网络能理解的方案进行格式化;这种格式化也因所使用网络的类型不同而不同。 表示层管理数据的解密与加密,如系统口令的处理。例如:在 Internet上查询你银行账户,使用的即是一种安全连接。你的账户数据在发送前被加密,在网络的另一端,表示层将对接收到的数据解密。除此之外,表示层协议还对图片和文件格式信息进行解码和编码。
应用层: 负责对软件提供接口以使程序能使用网络服务。术语“应用层”并不是指运行在网络上的某个特别应用程序 ,应用层提供的服务包括文件传输、文件管理以及电子邮件的信息处理。
inet_ntop
Linux下inet_pton和inet_ntop这2个IP地址转换函数,可以在将IP地址在“点分十进制”和“整数”之间转换。而且,这2个函数能够处理ipv4和ipv6。算是比较新的函数了。
inet_pton函数原型如下[将“点分十进制” -> “整数”]
#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
这个函数转换字符串到网络地址,第一个参数af是地址族,转换后存在dst中。inet_pton 是inet_addr的扩展,支持的多地址族有下列:
af = AF_INET src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址转换为in_addr的结构体,并复制在*dst中,dst应该指向大于等于32字节的空间。
af =AF_INET6 src若为指向IPV6的地址,函数将该地址转换为in6_addr的结构体,并复制在*dst中,dst应该指向大于等于128字节的空间。
如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0。
inet_ntop函数原型如下[将“整数” -> “点分十进制”]
#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h>
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和上面相同,只是多了一个参数socklen_t cnt,他是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC。
1.struct sockaddr
这个结构用来存储套接字地址。
数据定义:
struct sockaddr {
unsigned short sa_family; /* address族, AF_xxx */
char sa_data[14]; /* 14 bytes的协议地址 */
};
sa_family 一般来说,都是 “AFINET”。
sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一
切的。
为了处理 struct sockaddr, 程序员建立了另外一个相似的结构struct sockaddr_in:
struct sockaddr_in (“in” 代表 “Internet”)
struct sockaddr_in {
short int sin_family; /* Internet地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* Internet地址 */
unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/
};
这个结构提供了方便的手段来访问 socket address(struct sockaddr)结构中的每一个元
素。注意 sin_zero[8] 是为了是两个结构在内存中具有相同的尺寸,使用 sockaddr_in 的时
候要把 sin_zero 全部设成零值(使用 bzero()或 memset()函数) 。而且,有一点很重要,就
是一个指向 struct sockaddr_in 的指针可以声明指向一个 sturct sockaddr 的结构。所以虽然
socket() 函数需要一个 structaddr * ,你也可以给他一个 sockaddr_in * 。注意在 struct
sockaddr_in 中, sin_family 相当于 在 struct sockaddr 中的sa_family, 需要设成 “AF_INET”。
最后一定要保证 sin_port 和sin_addr 必须是网络字节顺序(见下节)!
2.struct in_addr
其定义如下:
struct in_addr {
unsigned long s_addr;
};
如果你声明了一个 “ ina ”作为一个 struct sockaddr_in 的结构,那么
“ina.sin_addr.s_addr”就是 4 个字节的 IP 地址(按网络字节顺序排放) 。需要注意的是,
即使你的系统仍然使用联合而不是结构来表示 struct in_addr,你仍然可以用上面的方法得
到 4 个字节的IP 地址(一些 #defines 帮了你的忙)。
6.5.2 基本转换函数
在前面提到了网络字节顺序。那么什么是网络字节顺序,它有什么特殊性,又如何将
我们通常使用的数据转换成这种格式呢?
1.网络字节顺序(大端格式,低地址存放高字节内容)
因为每一个机器内部对变量的字节存储顺序不同(有的系统是高位在前,底位在后,
而有的系统是底位在前,高位在后) ,而网络传输的数据大家是一定要统一顺序的。所以
对与内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换(比如 IP 地
址的表示,端口号的表示) 。但是内部字节顺序和网络字节顺序相同的机器该怎么办呢?
是这样的:它们也要调用转换函数,但是真正转换还是不转换是由系统函数自己来决定的。
2.有关的转化函数
我们通常使用的有两种数据类型:短型(两个字节)和长型(四个字节) 。下面介绍
的这些转换函数对于这两类的无符号整型变量都可以进行正确的转换。
如果你想将一个短型数据从主机字节顺序转换到网络字节顺序的话,有这样一个函
数:它是以“h”开头的(代表“主机”) ;紧跟着它的是“to” ,代表“转换到” ;然后是“n”
代表“网络” ;最后是“s” ,代表“短型数据”。H-to-n-s,就是 htons() 函数(可以使用 Host
to Network Short 来助记)
s用于对2字节端口号操作,l用于对4字节IP数值进行操作
你可以使用 “n”, “h”, “to”, “s”, “l”的任意组合……当然,你要在可能的情况下
进行组合。比如,系统是没有 stolh() 函数的(Short to Long Host?)。
下面给出套接字字节转换程序的列表:
下面四个函数都是数字之间转换,不是在字符与数字之间
l htons()——“Host to Network Short” 主机字节顺序转换为网络字节顺序(对无符号
短型进行操作 2 bytes)
MYPORT=100;
my_addr.sin_port = htons(MYPORT) ;//将100转换为大端格式
l htonl()——“Host to Network Long” 主机字节顺序转换为网络字节顺序(对无符
ADDR=1000;
my_addr.sin_addr.s_addr = htonl(ADDR);
号长型进行操作 4 bytes)
l ntohs()——“ Network to Host Short “ 网络字节顺序转换为主机字节顺序(对无符
号短型进行操作 2 bytes)
l ntohl()——“ Network to Host Long “ 网络字节顺序转换为主机字节顺序(对无符
号长型进行操作 4 bytes)
注意:现在你可能认为自己已经精通于这几个函数的用处了……你可能会想: “恩……在我的 68000
机器内部,字节的表示顺序已经是网络字节顺序了,那么我的程序里就不必调用htonl() 来转换我的IP 地
址了” 。是的,你可能是对的。但是假如你把你的程序移植到一个内部字节顺序和网络字节顺序相反的机
器上,你的程序就会运行不正常!所以,一定要记住:在你把数据发送到 Internet 之前,一定要把它的字
节顺序从主机字节顺序转换到网络字节顺序!
在 struct sockaddr_in 中的 sin_addr 和 sin_port 他们的字节顺序都是网络字节顺序,而
sin_family 却不是网络字节顺序的。为什么呢?
这个是因为 sin_addr 和sin_port 是从IP 和 UDP 协议层取出来的数据,而在IP和 UDP
协议层,是直接和网络相关的,所以,它们必须使用网络字节顺序。然而, sin_family 域
只是内核用来判断 struct sockaddr_in 是存储的什么类型的数据,并且, sin_family 永远也
不会被发送到网络上,所以可以使用主机字节顺序来存储。
3.IP 地址转换
很幸运, Linux 系统提供和很多用于转换 IP 地址的函数,使你不必自己再写出一段
费力不讨好的子程序来吃力的变换 IP。
首先,让我假设你有一个 struct sockaddr_in ina,并且你的 IP 是 166.111.69.52 ,你想
把你的 IP 存储到 ina 中。你可以使用的函数: inet_addr() ,它能够把一个用数字和点表
示 IP地址的字符串转换成一个无符号长整型。你可以像下面这样使用它:
ina.sin_addr.s_addr = inet_addr(“ 166.111.69.52” );
注意:
inet_addr() 返回的地址已经是网络字节顺序了,你没有必要再去调用 htonl() 函数,是不是很
方便呢?
上面的用法并不是一个很好的习惯,因为上面的代码没有进行错误检查。如果 inet_addr() 函数
执行错误,它将会返回 – 1……等等!二进制的无符号整数值 – 1相当于什么?相当于255.255.255.255 !! 一
个广播用的IP 地址!没有办法,你只能在你自己的程序里进行对症下药的错误检查了。
好,现在我们已经可以把字符串的 IP 地址转换成长整型了。那么还有没有其他的方法
呢?如果你有一个 struct in_addr 并且你想把它代表的 IP 地址打印出来(按照 数字.数字.数
字.数字的格式)……
这里,你可以使用函数 inet_ntoa()( “ntoa”代表“Network to ASCII”):
printf(“ %s” , inet_ntoa(ina.sin_addr));
这段代码将会把 struct in_addr 里面存储的网络地址以 数字.数字.数字.数字 的格式显
示出来。
char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
注释: 本函数将一个用in参数所表示的Internet地址结构转换成以“.” 间隔的诸如“a.b.c.d”的字符串形式。
若无错误发生,inet_ntoa()返回一个字符指针。否则的话,返回NULL。其中的数据应在下一个WINDOWS套接口调用前复制出来。
注意:
inet_ntoa() 使用struct in_addr作为一个参数,不是一个长整型值。
inet_ntoa() 返回一个字符指针,它指向一个定义在函数 inet_ntoa() 中的 static 类型字符串。所
以每次你调用inet_ntoa(),都会改变最后一次调用inet_ntoa() 函数时得到的结果。
比如:
char *a1, a2;
a1 = inet_ntoa(ina1.sin_addr); /* this is 166.111.69.52 */
a2 = inet_ntoa(ina2.sin_addr); /* this is 166.111.69.53 */
printf(“address 1: %s\n” ,a1);
printf(“address 2: %s\n” ,a2);
将会显示出:
address 1: 166.111.69.53
address 2: 166.111.69.53
原型:in_addr_t inet_addr(const char *cp); //未socket、bind即可使用
功能:将一个点分十进制的IP转换成一个长整数型数(u_long类型),以网络字节序返回
#include <unistd.h>
int gethostname(char *hostname, size_t size);//未socket、bind即可使用
参数说明如下:
hostname 是一个指向字符数组的指针,当函数返回的时候,它里面的数据就是本
地的主机的名字,并不是域名,可以传递给gethostbyname获得hostent结构,hostname必须是一个已经开辟了空间的地址
size 是 hostname 指向的数组的长度.
函数如果成功执行,它返回 0,如果出现错误,则返回–1,全局变量 errno 中存储着错
误代码。
#include<sys/socket.h>
int getsockname( SOCKET s, struct sockaddr FAR* name, int FAR* namelen); //需要socket,但可以是连接或者未连续的socket
s:标识一个已捆绑套接口的描述字。
name:接收套接口的地址(名字)。
namelen:名字缓冲区长度。
注释: getsockname()函数用于获取一个套接口的名字。它用于一个已捆绑或已连接套接口s,本地地址将被返回。本调用特别适用于如下情况:未调用bind()就调用了connect(),这时唯有getsockname()调用可以获知系统内定的本地地址。在返回时,namelen参数包含了名字的实际字节数。 若一个套接口与INADDR_ANY捆绑,也就是说该套接口可以用任意主机的地址,此时除非调用connect()或accept()来连接,否则getsockname()将不会返回主机IP地址的任何信息。除非套接口被连接,WINDOWS套接口应用程序不应假设IP地址会从INADDR_ANY变成其他地址。这是因为对于多个主机环境下,除非套接口被连接,否则该套接口所用的IP地址是不可知的。
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);//需要socket、bind、accept可使用,因为返回的
是对方的hostname
下面是参数说明:
sockfd 已连接套接口的描述字,如用accept()返回的socket。
addr 是一个指向struct sockaddr (struct sockaddr_in 可以使用类型转换)的指针。
addrlen 是一个指向 int 的指针,应该赋于 sizeof(struct sockaddr)的大小。
如果在函数执行过程中出现了错误,函数将返回 –1 ,并且错误代码储存在全局变量
errno 中。
当你拥有了远程连接用户的 IP 地址,你就可以使用 inet_ntoa() 或 gethostbyaddr()来输
出信息或是做进一步的处理。
#include <netdb.h>
struct hostent *gethostbyname(const char *name);//未socket、bind、accept即可使用,如查询外网,则需要接入网络
这个函数的传入值是域名或者主机名
正如你所看见的,它返回了一个指向 struct hostent 的指针.Struct hostent 是这样定义
的:
struct hostent {
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
};
#define h_addr h_addr_list[0]
下面是上面各个域代表含义的解释:
h_name 是这个主机的正式名称,正规的主机名字(PC。
h_aliases 是一个以 NULL(空字符)结尾的数组,里面存储了主机的备用名称。
h_addrtype 是返回地址的类型,一般来说是“AF_INET”。
h_length 是地址的字节长度。
h_addr_list 是一个以 0 结尾的数组,存储了主机的网络地址,以网络字节序,没有圆点,但char *是字符型,要想获得值需要用强制类型转换,如inet_ntoa(*((struct in_addr *)(h_addr_list[0])))
注意:网络地址是以网络字节顺序存储的,但是字符型不受影响,因为它本身只有一个字节。
h_addr:是h_addr_list 数组的第一个成员.
gethostbyname() 返回的指针指向结构struct hostent , 如果发生错误, 它将会返回 NULL
(但是 errno 并不代表错误代码, h_errno 中存储的才识错误代码。 参考下面的herror()函数)。
应该如何使用这个函数呢?它看起来有一点点吓人。相信我,它使用起来远远要比它
看起来容易。
struct hostent FAR *PASCAL FAR gethostbyaddr(const char FAR * addr, int len, int type); //未socket、bind、accept即可使用,如查询外网,则需要接入网络
addr:指向网络字节顺序地址的指针。
例如,struct sockaddr_in s;unsigned int IP=110;
则s.sin_addr.s_addr=htonl(IP);即addr=(char *)&(s.sin_addr);len=sizeof(s.sin_addr);type=AF_INET;
len: 地址的长度,在AF_INET类型地址中为4。
type:地址类型,应为AF_INET。
与下面这个函数相似:
#include <netdb.h>
struct netent *getnetent(void)//未socket、bind、accept即可使用,如查询外网,则需要接入网络
Arguments:null
struct netent *getnetbyname(const char *name)//未socket即可使用,如查询外网,则需要接入网络
Arguments:
name:given a network name, pointed to by the name argument
struct netent * getnetbyaddr( uint32_t net, int type);//未socket即可使用,如查询外网,则需要接入网络
Arguments:
net
The net address whose network entry you want to find.
type
The address type. This must currently be AF_INET.
#include <netdb.h>
struct netent {
char * n_name;
char ** n_aliases;
int n_addrtype;
uint32_t n_net; //网络号,不是IP
};
n_name
The name of the network.
n_aliases
A zero-terminated list of alternate names for the network.
n_addrtype
The type of the network number returned; eg: AF_INET.
n_net
The network number. Network numbers are returned in network byte order.
select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组, 每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他 文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成, 当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执 行了select()的进程哪一Socket或文件可读。 阻塞式I/O编程有两个特点:
一、如果一个发现I\O有输入,读取的过程中,另外一个也有了输入,这时候不会产生任何反应.这就需要你的程序语句去用到select函数的时候才知道有数据输入。
二、程序去select的时候,如果没有数据输入,程序会一直等待,直到有数据位置,也就是程序中无需循环和sleep。 Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。 可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。编辑本段操作程序 下面具体解释:
#include <sys/types.h>
#include <sys/times.h>
#include <sys/select.h>
int select(nfds, readfds, writefds, exceptfds, timeout) 返回就绪文件描述符个数
int nfds;
fd_set *readfds, *writefds, *exceptfds;
struct timeval *timeout;
ndfs:select监视的文件句柄数,视进程中打开的文件数而定,一般设为你要监视各文件中的最大文件号加一。
readfds:select监视的可读文件句柄集合。
writefds: select监视的可写文件句柄集合。
exceptfds:select监视的异常文件句柄集合。
timeout:本次select()的超时结束时间。(见/usr/sys/select.h,可精确至百万分之一秒!)
FD_ZERO(fd_set *fdset):清空fdset与所有文件句柄的联系。
FD_SET(int fd, fd_set *fdset):建立文件句柄fd与fdset的联系。
FD_CLR(int fd, fd_set *fdset):清除文件句柄fd与fdset的联系。
FD_ISSET(int fd, fd_set *fdset):检查fdset联系的文件句柄fd是否可读写,当>0表示可读写。
(关于fd_set及相关宏的定义见/usr/include/sys/types.h)
INADDR_ANY一般是0,表示由系统自动选择自己一个合适的IP监听,因为一个电脑可能有多个网卡,对应多个IP,但端口号一般要固定
#include <sys/types.h>
#include <sys/socket.h>
int bind (int sockfd , struct sockaddr *my_addr , int addrlen) ;
参数说明:
sockfd 是由socket()函数返回的套接字描述符。
my_addr 是一个指向 struct sockaddr 的指针,包含有关你的地址的信息:名称、端口和 IP地址。
IP可以是INADDR_ANY,但是端口号必须是指定的,用于让用户绑定的
addrlen 可以设置为 sizeof(struct sockaddr)。
struct servent *getservbyname(const char * name, const char *proto); //proto为tcp udp等等
gethostbyname和gethostbyaddr这两个函数仅仅支持IPv4,getaddrinfo函数能够处理名字到地址以及服务到端口这两 种转换,返回的是一个sockaddr结构的链表而不是一个地址清单。这些sockaddr结构随后可由套接口函数直接使用。如此以 来,getaddrinfo函数把协议相关性安全隐藏在这个库函数内部。应用程序只要处理由getaddrinfo函数填写的套接口地址结构。该函数在 POSIX规范中定义了。
函数原型:
int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result ); 参数说明:
hostname:一个主机名或者地址串(IPv4的点分十进制串或者IPv6的16进制串)
service:服务名可以是十进制的端口号,也可以是已定义的服务名称,如ftp、http等
hints:可以是一个空指针,也可以是一个指向某个addrinfo结构体的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:如果指定的服务既支持TCP也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM使得返回的仅仅是适用于数据报套接口的信息。一般定义struct addrinfo s;再对s进行一些设置,最后,hints=&s; ai_canonname ai_addr ai_next常设置为NULL,但由result返回时,里面并不为空。
result:本函数通过result指针参数返回一个指向addrinfo结构体链表的指针,可以定义一个struct addrinfo *p; 则设置为reustl=&p;。
由于返回的是一个链表,因此查询整个链表方法为:sturct addrinfo *aip;
for(aip=p;aip!=NULL;aip=aip->ai_next)
{
//对于多网卡,一个网上对应一个IP,可能会返回多个ai_addr,而一个ai_addr也可能对应多个ai_protocol,所以可能要循环多次
}
typedef struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfo* ai_next;
};
参数 取值 值 说明
ai_family
AF_INET 2 IPv4
AF_INET6 23 IPv6
AF_UNSPEC 0 协议无关
ai_protocol IPPROTO_IP 0 IP协议,网络层协议
IPPROTO_IPV4 4 IPv4
IPPROTO_IPV6 41 IPv6
IPPROTO_UDP 17 UDP,传输层协议
IPPROTO_TCP 6 TCP
IPPROTO_RAW 255
ai_socktype SOCK_STREAM 1 流
SOCK_DGRAM 2 数据报
ai_flags AI_PASSIVE 1 被动的,用于bind,通常用于server socket
AI_CANONNAME 2
AI_NUMERICHOST 4 地址为数字串
0 默认
INADDR_ANY 为(0.0.0.0) 表示任何可绑定的地址; INADDR_BROADCAST为 (255.255.255.255) 表示任何主机,由于历史的原因,这与绑定为 INADDR_ANY 有同样的效果.