socket可以看成是用户进程与内核网络协议栈的编程接口。socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信。
内容概括:
1.初识socket
2.IPv4套接口地址结构
3.通用地址结构
4.网络字节序
5.字节序转换函数
6.地址转换函数
7.套接字类型
- 初识socket
- IPv4套接口地址结构
(1)IPv4套接口地址结构通常也称为“网际套接字地址结构”,它以“sockaddr_in”命名,定义在头文件<netinet/in.h>中:
12345struct sockaddr_in {sa_family_t sin_family; /* address family: AF_INET */in_port_t sin_port; /* port in network byte order */struct in_addr sin_addr; /* internet address */};
1)sin_family:指定该地址家族,在这里必须设为AF_INET。
2)sin_port:端口。
3)sin_addr:IPv4的地址。 - 通用地址结构
通用地址结构用来指定与套接字关联的地址:
12345struct sockaddr {unit8_t sin_len;sa_family_t sin_family;char sa_data[14];}
1)sin_len:整个sockaddr结构体的长度。
2)sin_family:指定该地址家族。
3)sa_data:由sin_family决定它的形式。 - 网络字节序
(1)字节序
1)大端字节序(Big Endian):最高有效位(MSB:Most Significant Bit)存储于最低内存地址处,最低有效位(LSB)存储于最高内存地址处。
2)小端字节序(Small Endian):最高有效位存储于最高内存地址处,最低有效位存储于最低内存地址处。
(2)主机字节序
不同的主机有不同的字节序,如X86为小端字节序,Motorola 6800为大端字节序,ARM字节序是可配置的。
(3)网络字节序
网络字节序规定为大端字节序。
(4)测试自己的主机是大端字节序还是小端字节序:
123456789#include <stdio.h>int main(void){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 0;}
输出:
123$ gcc -o byteorder byteorder.c$ ./byteorder78 56 34 12
结果显示:最低有效位(78)存储在低内存地址处,是小端字节序。 - 字节序转换函数
下面4个函数在头文件<arpa/inet.h>中:
(1)uint32_t htonl(uint32_t hostlong);
(2)uint16_t htons(uint16_t hostshort);
(3)unint32_t ntohl(uint32_t netlong);
(4)unint16_t ntohs(uint16_t netshort);
说明:上述函数中,h代表host;n代表network;s代表short;l代表long。
示例:将主机字节序转换成网络字节序,并输出对比:
1234567891011121314#include <stdio.h>#include <arpa/inet.h>int main(void){unsigned int x = 0x12345678;unsigned char *p = (unsigned char*)&x;printf("%0x %0x %0x %0x\n", p[0], p[1], p[2], p[3]);unsigned int y = htonl(x);p = (unsigned char*)&y;printf("%0x %0x %0x %0x\n", p[0], p[1], p[2], p[3]);return 0;}
输出:
1278 56 34 1212 34 56 78
果然,本主机字节序与网络字节序是相反的。 - 地址转换函数
123456#include <netinet/in.h>#include <arpa/inet.h>int inet_aton(const char *cp, struct in_addr *inp);in_addr_t inet_addr(const char *cp);char *inet_ntoa(struct in_addr in);
(1)示例1:inet_addr函数将一个点分十进制的ip地址转换成一个网络字节序的32位整数,再以主机字节序打印:
123456789#include <stdio.h>#include <arpa/inet.h>int main(void){unsigned long addr = inet_addr("192.168.0.100");printf("addr=%u\n", ntohl(addr));return 0;}
输出:
1addr=3232235620
(2)示例2:inet_ntoa将一个地址结构转换成点分十进制的ip地址:
12345678910111213#include <stdio.h>#include <arpa/inet.h>int main(void){unsigned long addr = inet_addr("192.168.0.100");printf("addr=%u\n", ntohl(addr));struct in_addr ipaddr;ipaddr.s_addr = addr;printf("%s\n", inet_ntoa(ipaddr));return 0;}
输出:
12addr=3232235620192.168.0.100
(3)inet_aton函数功能跟第二个函数一样。 - 套接字类型
(1)流式套接字(SOCK_STREAM)
提供面向连接的、可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接受。
(2)数据报式套接字(SOCK_DGRAM)
提供无连接服务。不提供无错保证,数据可能丢失或重复,并且接受顺序混乱。
(3)原始套接字(SOCK_RAW)