Network Programming(六)
网络编程进阶
Network services网络服务
服务与端口相关联
ports分三类:
- well-known ports (0到1023)是基本服务(系统使用,需要超级用户特权)
- referenced ports 参考端口(1024至49151)由IANA根据请求实体的申请为特定服务关联(在大多数系统上,普通用户可以使用注册端口)。
- Dynamic or private or ephemeral ports 动态或私有或短暂端口(49152至65535)用于其他目的。
与服务相关文件
Services databasefile - /etc/services
servant 数据结构
有set of functions用于连接服务列表
其中两个返回一个指向struct的指针,这个struct包含关于service的信息。
定义在<netdb.h>
struct servent{
char s_name;
char** s_aliases;
int s_port;
char s_proto;
}
- s_name:官方服务名称
- s_aliases:以NULL结尾的服务替代名称列表
- s_port:按网络字节顺序给出的服务端口号
- s_proto:与此服务一起使用的协议的名称
获取服务信息(函数)
函数一:
struct servent getservbyname(const char name,const char* proto)
name是服务名,proto是协议名
从数据库返回与使用协议原型匹配的服务名称的条目的servents结构的函数。
如果protois为NULL,则将匹配任何协议。
如有必要,将打开与数据库的连接.
定义在 netdb.h
返回指向静态分配的servents结构的指针,
如果发生错误或到达文件末尾,则返回NULL。
函数二:
struct servent getservbyport(int port,const char proto)
port是端口号
proto是协议
和上一个函数相似,不多加说明
协议文件
/etc/protocols
协议数据结构
同样定义在netdb.h
struct protoent{
char* p_name;
char** p_aliases;
int p_proto;
}
p_name: 协议的官方名
p_aliases: 以NULL结尾的协议其他代替名列表
p_proto: 协议号
获取协议信息的函数
struct protoent getprotobyname(const char name)
name是协议名
struct protoent* getprotobynumber(int proto)
proto是相关数字
主机文件
/etc/hosts
host数据结构
struct hostent{
char* h_name;
char h_aliases;
int h_addrtype;
int h_length;
char h_addr_list;
}
h_name: host官方名
h_aliases: 代替名
h_addrtype: 地址类型:AF_INET or AF_INET6
h_length: 地址长度 bytes
h_addr_list 列表指向主机网络地址的指针数组(按网络字节顺序),由空指针终止。
为了保证向后兼容性,h addr(h addr列表中与主机关联的第一个网络地址)被定义为:# define h_addr h_addr_list[0]
获取主机信息
struct hostent gethostbyname(const char name)
如果名称是一个IPv4地址,则不执行查找,gethostbyname()只是将名称复制到返回主机结构的h _ name字段中,并将它的结构添加到h _ addr _ list[0]字段中。
返回值:hostent structure 出错时,null,h_errno(在netdb.h中定义)变量保存一个错误号。使用herror(char* s)产生相应的错误信息
struct hostent gethostbyaddr(const void addr, socklen_t len,int type)
addr : IP地址
len:长度
type: AF_INET or AF_INET6 (#include <sys/socket.h>)
host_address参数是一个指针,指向一个类型取决于地址类型的结构,例如地址类型AF_INET的结构地址(可能是通过调用inet_addr(3))获得的。
返回值:hostent structure 出错时,null,出错时,h_errno(在netdb.h中定义)变量保存一个错误号。使用herror(char s)产生相应的错误信息
UDP sockets的multicast多播和broadcast广播
怎么发送data给多个接收者?
法一:unicast data的copy到每个接收者(没有效率)
法二:使用network support
Broadcasting:发送一个datagram所有在到达的子网上的主机都会接受
子网中的每台主机都必须通过UDP层处理数据报,以防万一,即使主机不参与应用程序。这也可能会造成过多的处理负载
Multicasting:一个message仅发送给主机的子集
任何人都可以加入多播组
任何人都可以发送给多播组
只有UDP sockets可以广播和多播
- 两种广播地址:子定向广播地址(example192.168.66.255 for a subnet192.168.66.0/24)受限的广播地址255.255.255.255
- 不应该由路由器转发
- 为了使用广播,必须更改套接字的选项
1 | int breadcastPermission=1; |
SO_BROADCAST很重要
- 对于多播,使用D类地址:224.0.0.0 to 239.255.255.255; IPv4地址的前四位设置为1110
- 有一些特殊的组播组 - “众所周知的组播组”,由于分配给它们的特殊用途,不应在应用程序中使用:
224.0.0.1是全主机组。
–224 . 0 . 0 . 2是全路由器组。
–224 . 0 . 0 . 4是全DVMRP路由器,224.0.0.5是全OSPF路由器,224.0.013是全无源互调路由器,等等。
–224 . 0 . 0 . 0至224.0.0.255保留用于本地目的(作为管理和维护任务)
–239 . 0 . 0 . 0至239.255.255.255也保留用于管理目的。为了发送一个多播UDP数据报:
- 打开一个UPDsocket,填充D类地址
- 不需要改变socket options
- 需要设置TTL(time-to-live),为了限制数据包中继的跳数
- setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,(void*)&multicastTTL,sizeof(multicastTTL))
- 当TTL为0,packet被丢弃
- 使用setsockopt( )关闭环回,这样可以避免接收正在发送的数据包
为了接受一个多播UDP数据报:
-创建一个SOCK_DGRAM socket()
-bind一个多播地址和port- 使用setsockopt()加入多播组,设置IP_ADD_MEMBERSHIP
- 这告诉系统在网络上接收目的地是多播组地址的数据包。
- 使用ip _ mreq structureto指定多播组地址和要使用的接口(使用0.0.0.0表示任何接口)
- 使用recvfrom()来接受多播数据报
- 使用setsockopt()加入多播组,设置IP_ADD_MEMBERSHIP
例子如下
UDP多播设置