网络编程基础
网络编程基础
1、套接字概念
Linux环境下使用套接字进行进程之间的通信。用过套接字的接口,其他进程的位置对于应用程序来讲是透明的。相互通信双方端点都有一个套接字,双方如果要进行通信,通过套接字建立桥梁,双方就可以通信了。
类似文件一样,套接字也有一个套接字描述符,应用程序可以像操作文件一样操作套接字。在进行网络通信的过程中,用户感觉就是在操作文件一样,这是Linux将外部设备抽象为一个文件的好处。
2、字节序
不同主机的体系结构不同,所采用的数据存储方式不同。网络中,进程之间的通信是跨主机的,这样会出现字节序不一样的问题。为了能够解决好这个问题,网络协议提供一种字节序,无论主机是什么字节序,在进行网络传输的时候,先转换成网络字节序,到接收端再对应主机转换字节序。
Linux环境下使用下面四个函数进行字节序转换:
uint32_t htonl(uint32_t hostint32);是将主机字节序转换成网络字节序,参数是32位本地主机数据。
uint16_t htons(uint16_t hostint16); 是将主机字节序转换成网络字节序,参数是16位本地主机数据。
uint32_t ntohl(uint32_t hostint32); 是将网络字节序转换成主机字节序,参数是32位本地主机数据。
uint16_t ntohs(uint16_t hostint16); 是将网络字节序转换成主机字节序,参数是16位本地主机数据。
3、地址格式
网络环境中每一个主机都有一个唯一标识自己的地址,这个地址就是IP地址,IP地址由一个32位的整数组成,每8位作为一个独立的数字,用“.”分开。例如:192.168.1.1,“.”与“.”之间时8位,因此最大值是225。
Linux中使用in_addr结构表示一个IP地址,结构体定义如下:
struct in_addr
{
in_addr_t s_addr; // in_addr_t被定义为无符号整形
}
Linux中的网络通信地址格式
struct sockaddr_in
{
sa_family_t sin_family; ///16位的地址族
in_port_t sin_port; ///16位的端口号
struct in_addr sin_addr; ///32位的IP地址
unsigned char sin_zero[8]; ///填充区,8个字节填“0”
}
该结构体中最后一个成员表示填充区,保证sockaddr_in正好16个字节。这样的目的是为了socketaddr_in结构可以和sockaddr地址结构可以随意转换。Socketaddr结构体定义如下:
struct socketaddr
{
sa_family sa_family; ///16位地址族
char sa_data[14]; ///14字节的填充
}
这两个结构体定义等长,socketaddr结构中的sa_data成员实际可以看成是由sin_port、sin_addr、sin_zero这三个成员变量组成的。
4、地址形式转换
IP地址是以二进制的形式存储在地址结构中的,观察不方便,因此需要转化成点分十进制表示IP地址更加直观,可以使用下面的函数进行格式转换。
const char * inet_ntop(int domain, const void * restrict addr, char * restrict str, socklen_t size);是将二进制地址转换为字符串形式的地址,成功返回首地址,二进制格式错误返回0,函数错误返回-1。’
inti net_pton(int domain, const char * restrict str, void * restrict addr);是将字符串形式的地址转换成二进制形式的地址。
上述两个函数中,domain参数值可以是AF_INET或者是AF_INET6分别表示IPv4协议或者IPv6协议。
5、地址映射
对于用户来说,套接字的结构信息是不必要的,用户只需要传递一个sockaddr_in地址结构的地址,之后由系统填充就可以了。
网络环境中服务器需要提供一个唯一的IP地址和一个主机名(域名)。对于大多数服务器来说,客户端往往不知道其准确的IP地址,只知道域名,这种情况下用户可以求助于DNS服务器。该服务器可以将域名转换成IP地址。
转换后的IP地址和端口号存储在一个addrinfo的地址信息结构中,Linux环境下提供一个函数,根据用户指定的服务器域名和服务器名称得打服务器的IP地址和端口号,并写到一个sockaddr_in地址结构中。函数如下:
int fetaddrinfo(const char * restrict host, const char * restrict service, const struct addrinfo * restrict hint, struct addrinfo ** restrict res);
函数中前两个参数表示需要访问的主机名和服务的名称。这两个名称应该都已经在DNS服务器中注册过。第三个参数表示一个过滤地址模板,一般设置为NULL,第4个参数表示一个地址信息结构列表。该表列出来所有可能的符合条件的地址结构,用户可以从中任选一个作为通信的地址。如果成功得到地址信息列表,函数返回0,失败返回-1。