套接字1
socket套接字(1)
在Linux中的网络编程是通过socket接口来进行的,它也是一种文件描述符。socket是一种常用的进程之间通信机制,通过它不仅能实现本地机器上的进程之间的通信,而且通过网络能够在不同机器上的进程之间进行通信。
每一个Socket 都用一个半相关描述:
{协议,本地地址,本地端口}
一个完整的Socket 则用一个相关描述:
{协议,本地地址,本地端口,远程地址,远程端口}
socket类型
常见的socket有3种类型:
流式socket(SOCK_STREAM) : 流式套接字提供可靠的、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性
数据报socket(SOCK_DGRAM) : 数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无需并且不保证可靠、无差错的。它使用数据报协议UDP
原始socket(SOCK_RAW) : 原始套接字允许对底层协议进行直接访问,它功能强大,但使用较为复杂,主要用于协议的开发
地址结构相关处理
地址相关的数据类型有以下两个:
1 |
|
这两个数据类型是等效的,可以互相妆化,通常sockaddr_in使用更加方便
sa_family可选值有:
- AF_INET : IPv4协议
- AF_INET6 : IPv6协议
- AF_LOCAL : UNIX域协议
- AF_LINK : 链路地址协议
- AF_KEY : 密钥套接字
数据存储有点顺序
计算机数据存储有两种字节优先顺序:高位字节优先(大端模式)和低位字节优先(小端模式),Internet上数据以高字节优先顺序在网络上传输,因此在有些情况下需要对这两个字节存储优先顺序进行相互转化。这里用到了4个函数:htons()、ntohs()、htonl()、ntohl()。这四个函数分别实现网络字节序和主机字节序的转化。h代表host,n代表network,s代表short,l代表long。通常16位的IP端口号用s代表,而IP地址用l代表。
1 |
|
地址格式转化
通常用户在表达地址时采用的是点分十进制表示的数值,而在socket编程中使用的是二进制值,这就需要将这两个值进行转换。IPv4中用到的函数有inet_aton()、inet_addr()和inet_ntoa(),IPv4和IPv6兼容的有inet_pton()和inet_ntop()。
1 |
|
名字地址转换
在Linux中实现主机名和地址的转换函数有:gethostbyname()、gethostbyaddr()和getaddrinfo()等。其中gethostbyname()是将主机名转化为IP地址,gethostbyaddr()则是逆操作
gethostbyname()、gethostbyaddr()都涉及一个hostent的结构体:
1 |
|
getaddrinfo()涉及一个addrinfo的结构体:
1 |
|
gethostbyname()
1 |
|
hostname : 主机名
成功返回hostent结构体指针,出错返回-1
getaddrinfo()
1 |
|
node : 网络地址或网络主机名
service : 服务名或十进制的端口号字串
hints : 服务线索
result : 返回结果
成功返回0,出错返回-1
在调用之前,首先要对hints服务器线索进行设置,下面给出addrinfo常见的选项值
ai_flags:
- AI_PASSIVE 该套接口是用作被动打开
- AI_CANONNAME 通知getaddrinfo函数返回主机的名字
ai_family:
- AF_INET IPv4协议
- AF_INET6 IPv6协议
- AF_UNSPEC IPv4或IPv6协议
ai_socktype :
- SOCK_STREAM 字节流套接字socket(TCP)
- SOCK_DGRAM 数据报套接字spcket(UDP)
ai_protocol:
- IPPROTO_IP IP协议
- IPPROTO_IPV4 IPv4协议
- IPPROTO_IPV6 IPv6协议
- IPPROTO_UDP UDP
- IPPROTO_TCP TCP
- 通常服务端在调用getaddrinfo()之前,ai_flag设置AI_PASSIVE,用于bind()函数,主机名会设置为NULL
- 客户端调用getaddrinfo()时,ai_flags一般不设置AI_PASSIVE,但是主机名和服务名不应该为空
getaddrinfo()用法
1 |
|