这篇笔记记录什么socket的认识。
1 什么是socket
socket可以看成是用户进程与内核网络协议栈的编程接口。
上图中,Application是用户空间,TCP IP是内核空间,用户空间想要访问内核中的网络协议,就要通过Socket接口。
socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信。比如,手机和电脑之间也可以通过网络进行通信。
2 IPV4套接字地址结构
ipv4接口有两种结构,分别是 网络套接字结构和通用套接字结构。
网络套接字地址结构
IPV4套接字地址结构通常也称为“网际套接字地址结构”,以sockaddr_in命名。
struct sockaddr_in
{
uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin_len:整个sockaddr_in结构体的长度;
sin_family:指定该地址家族,在这里必须设为AF_INET;
sin_port:端口
sin_addr:IPv4的地址;
sin_zero:暂不使用,一般将其设置为0;
通用套接字结构
struct sockaddr
{
uint8_t sin_len;
sa_family_t sin_family;
char sa_data[14];
};
sin_len: 整个sockaddr结构体的长度
sin_family: 指定该地址家族
sa_data: 由sin_family决定它的形式。
3 大小端
大端字节序:最高有效位存储于最低内存位置。
小端字节序:最高有效位存放在内存最高位置。
主机字节序:不同主机有不同字节序,大段和小端。
网络字节序:通常为大端字节序。
#include <stdio.h>
int main()
{
unsigned int x = 0x12345678;
unsigned char *p = (unsigned char *)&x;
printf("%0x %0x %0x %0x\n", p[0], p[1], p[2], p[3]);
return 1;
}
12是最高有效位,存放在了高地址p[3],所以是小端字节序。
4 字节转换函数
从网络端发送
h表示Host主机,
n表示network,
s表示short,
l表示 long int
uint32_t htonl(uint32_t hostlong);将32位主机序转为网络字节序;
uint16_t htons(uint16_t hostshort); 将16位主机序转为网络16位。
uint32_t ntohl(uint32_t netlong); 将32位网络字节序转为32主机字节序;
uint16_t ntohs(uint16_t netshort); 将16位网络字节序转为16位主机字节序。
代码
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
unsigned int x = 0x12345678;
unsigned char *p = (unsigned char *)&x;
printf("%0x %0x %0x %0x\n", p[0], p[1], p[2], p[3]);
// 输出结果 78 65 45 34 12
// 将主机字节序转为网络字节序
unsigned int y = htonl(x);
p = (unsigned char *)&y;
printf("%0x %0x %0x %0x\n", p[0], p[1], p[2], p[3]);
// 输出结果 12 34 56 78
return 1;
}
5 地址转换函数:int 转为 const char *
**将32位整数转为const char ***
in_addr_t inet_addr(const char *cp); // 将主机地址转为32位整数,比如192.168.1.1 转为 32位 整数, 发送数据时候,需要这样转换。
char *inet_ntoa(struct in_addr in); // 将地址结构转为点分十进制ip地址。 int inet_aton(const char *cp, struct in_addr *inp);
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
unsigned int addr = inet_addr("192.168.1.1"); // char * 转 uint
printf("addr=%u\n", ntohl(addr)); // 将网络字节序转为主机字节序
printf("addr=%u\n", addr);
// 将地址结构转为 点分十进制
struct in_addr ipaddr;
ipaddr.s_addr = addr;
printf("addr=%s\n", inet_ntoa(ipaddr)); // uint转char *
return 1;
}
6 套接字类型
- 流式套接字(SOCK_STREAM) 提供面向连接的、可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收。
- 数据报式套接字(SOCK_DGRAM) 提供无连接服务。不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。