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
2
int breadcastPermission=1;
setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(void*)&broadcastPermission,sizeof(broadcastPermission));

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()来接受多播数据报

例子如下

UDP多播设置