套接字(socket):地址+端口
是通信的基石,是支持TCP/IP协议的路通信的基本操作单元。
1、socket的信息数据结构
- sockaddr
struct sockaddr {
//地址族 AF_INET表示ipv4 AF_INET6表示ipv6
sa_family_t sa_family;
//14字节的协议地址,包含该socket的ip地址和端口号
char sa_data[14];
}
- sockaddr_in
是sockaddr的改进版
struct sockaddr_in {
//地址族
short int sin_family;
//端口号
unsigned short int sin_port;
//ip地址
struct in_addr sin_addr;
//填充0以保持和struct sockaddr大小一样
unsigned char sin_zero[8];
};
- in_addr
struct in_addr{
//32位ipv4地址,网络字节序
unsigned long int s_addr;
};
2、ipv4地址与二进制数字的转化
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef uint32_t in_addr_t;
//将ipv4地址转成二进制数字,失败返回-1
in_addr_t inet_addr(const char *cp);
//将ipv4地址转成二进制数字,把结果放在inp所指的内存中,失败返回0
int inet_aton(const char *cp, struct in_addr *inp);
//将二进制数字转成将ipv4地址,返回指向结果的指针
char *inet_ntoa(struct in_addr in);
//将二进制数字转换为ipv4或ipv6 ip地址。
const char *inet_ntop(int af, const void *src,
char *dst, socklen_t size);
//将ipv4或ipv6 ip地址转换为数字二进制形式
int inet_pton(int af, const char *src, void *dst);
3、网络字节序与主机字节序的转化
- 小端模式:低地址存放低字节
- 大端模式:低地址存放高字节
- 主机字节序有可能是大端或小端,网络字节序都是大端模式
#include <arpa/inet.h>
//将 32/16 位的主机字节序转化为网络字节序并返回
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
//将 32/16 位的网络字节序转化为主机字节序并返回
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
uint32_t 相当于 unsigned long int
uint16_t 相当于 unsigned short int
h 代表 host 、n 代表 network
s 代表 short、l 代表 long
4、验证
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void check(){
int i = 0x12345678;
char *p = (char *)&i;
if (*p == 0x12)
printf("主机为大端模式\n");
else
printf("主机为小端模式\n");
}
int main() {
char *ip = "192.168.200.100";
struct in_addr inp;
struct in_addr num;
inet_aton(ip,&inp);//地址转数字
num.s_addr = inet_addr(ip);//地址转数字
check();//判断主机大小端
printf("地址转数字(inet_aton): %x\n", inp.s_addr);
printf("地址转数字(inet_addr): %x\n", num.s_addr);
printf("网络转主机(ntohl): %x\n", ntohl( num.s_addr));
printf("主机转网络(htonl): %x\n", htonl( num.s_addr));
printf("数字转地址: %s\n", inet_ntoa(num));
}
11000000.10101000.11001000.01100100
c0.a8.c8.64
192.168.200.100
猜测ntohl和htonl都只是将大小端互换
5、主机名与地址转化
#include <netdb.h>
#include <sys/socket.h>
struct hostent *gethostbyname(const char *name);//将主机名转换为ip地址
struct hostent *gethostbyaddr(const void *addr,
socklen_t len, int type);
struct hostent {
char *h_name; /* 正式主机命 */
char **h_aliases; /* a主机别名 */
int h_addrtype; /* 主机ip地址类型 ipv4/ipv6 */
int h_length; /* 主机ip地址长度 */
char **h_addr_list; /* 主机ip地址列表 */
}
#define h_addr h_addr_list[0] /* 保存ip地址 */
参考:man手册,《高质量嵌入式linuxc编程 第2版》349-354