3.2 KiB
3.2 KiB
net
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <netdb.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
tips
+ 所有网络函数失败基本是返回 -1,errno被设置
socket
原型: int socket(int domain, int type, int protocol)
+ domain 协议族
\ PF_INET # IPv4 互联网协议族
\ PF_INET6 # IPv6 互联网协议族
\ PF_LOCAL # 本地通讯地址族
+ type 数据传输类型
\ SOCK_STREAM # 面向连接; 数据不丢失; 数据顺序不错乱; 双向通道;
\ SOCK_DGRAM # 无连接; 数据可能丢; 数据可能错乱; 效率高;
+ protocol 最终使用协议
\ IPPROTO_TCP
\ IPPROTO_UDP
\ 0 # 编译器自动识别
主机字节序和网络字节序
+ 大端序和小端序 (如果数据大于1B,CPU在内存中存放数据的方式)
\ 大端序 低位字节在高位,高位字节在低位
\ 小端序 低位字节在低位,高位字节在高位 (INTEL)
## 字节序不同的系统字节传输数据,可能会出现问题,所以网络字节序约定使用大端序
+ c提供了4个库用于主机字节序和网络字节序之间的转换
\ uint16_t htons(uint16_t hostshort); // 2字节的整数
\ uint32_t htonl(uint32_t hostshort); // 4字节的整数
\ uint16_t ntons(uint16_t netshort); // 2字节的整数
\ uint32_t ntonl(uint32_t netshort); // 4字节的整数
// h host主机
// to 转换
// n network网络
// s short(2byte)
// l long(4byte)
IP地址和通讯端口
+ IPv4(4byte) 端口(2byte)
大小端序的处理
+ 在网络编程中数据收发有自动转换,只有sockaddr_in结构成员变量填充数据时,才需要考虑字节序
结构体
## sockaddr
```cpp
struct sockaddr { // connect() bind() 都需要
unsigned short sa_family; // 协议族
unsigned char sa_data[14]; // 14byte的端口和地址
}
```
## sockaddr_in
```cpp
struct sockaddr { // 为了方便操作,大小与sockaddr相同,可以强制转换
unsigned short sin_family; // 协议族
unsigned short sin_port; // 2byte端口号
//struct in_addr sin_addr; // 4byte地址
unsigned int sin_addr; // 4byte地址
unsigned char sin_zero[8]; // 保留,长度对齐
}
```
gethostbyname函数
+ 用 域名/主机名/字符串IP 转换成大端序
```cpp
struct hostent *gethostbyname(const char *name);
struct hostent {
char *h_name; // 主机名
char **h_aliases; // 主机所有别名的字符串数组
short h_addrtype; // 主机IP类型,IPv4或IPv6
short h_length; // 主机IP长度
char **h_addr_list; // 主机IP地址,以网络字节序存储
}
#define h_addr h_addr_list[0]
// 转换后,用 memcpy(&servaddr.sin_addr, h->h_addr, h->h_length);
```
字符串IP和大端序IP的转换
## atoi() 把字符串IP转换成大端序
```cpp
typedef unsigned int in_addr_t; //4byte大端序IP
// 字符串转大端序IP,转换后IP赋给sockaddr_in.in_addr.s_addr
in_addr_t inet_addr(const char *cp);
// 字符串转大端序IP,转换后IP赋给sockaddr_in.in_addr
int inet_aton(const char *cp, struct in_addr *inp);
//大转字符串,用于服务端解析IP
char *inet_ntoa(struct in_addr in);
```