socket能够当作是用户进程与内核网络协议栈的编程接口。TCP/IP协议的底层部分已经被内核实现了,而应用层是用户须要实现的,这部分程序工做在用户空间。用户空间的程序须要经过套接字来访问内核网络协议栈。html
套接口是全双工的通讯,它不只能够用于本机的进程间通讯,还能够用于网络上不一样主机的进程间通讯。编程
套接字还能够异构系统间进行通讯,异构系统指的是在硬件或软件上有所差异的系统,例如安卓系统的手机与windows系统的PC机上均可以实现QQ通讯,套接字能够实如今这两个设备上的通讯。windows
套接口既然可以链接两个端系统,那它就须要一个地址来标记该端系统,例如两个电话须要电话号码来标记才能够进行拨号。这抽象成套接口的地址结构。IPV4套接口地址结构一般也称为“网际套接字地址结构”,它以sockaddr_in命名,定义在头文件< netinet/in/h >中。网络
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]; };
说明:socket
其中,struct in_addr仅仅是一个32位的无符号整数,能够在终端下输入man 7 ip进行查看:函数
接下来看一下通用的地址结构。上面说过,socket能够用于不一样的协议上,通用的地址结构能够用于任何协议的socket编程。测试
struct sockaddr{ uint8_t sin_len; sa_family sin_family; char sa_data[14]; };
说明:ui
能够看到,在通用地址结构中sa_data是14个字节,而在IPV4的地址结构中,sin_port、sin_addr、sin_zero三个变量加起来也等于14个字节。也便是说,这两种结构是兼容的。设计
字节序能够分为大端字节序与小端字节序:unix
这样提及来挺抽象,经过一幅图来讲明:
上面说过,socket能够用于异构系统之间的通讯。而不一样的系统采用的字节序多是不一样的,有的系统采用大端字节序,例如Motorola 6800;有的采用小端字节序,如X86。所以,在进行字节传输时,应该同一一个字节序,称为网络字节序。网络字节序采用大端字节序。若是主机A为小端字节序的系统,那么在传输时须要先将小端字节序转换成网络字节序。这须要一些字节序的转换函数。
咱们能够编写程序来测试本身的主机是什么字节序:
#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; }
在个人电脑上输出结果为:78,56,34,12. 所以个人主机为小端字节序。
若是主机的字节序与网络字节序不一样,那么须要进行字节序的转换。下面是一些字节序转换函数:
# include < arpa/inet.h > uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);
说明:h表明host;n表明network;s表明short;l表明long
描述:
咱们能够进行验证,刚才已经经过程序测试出个人主机是小端字节序,接下来使用函数 htonl()将整数0x12345678转换成网络字节序。
#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; }
结果输出:
转换前:78,56,34,12
转换后:12,34,56,78
对于IP地址,咱们一般采用点分十进制的形式进行直观的认识,而程序更多的时候是处理32位的地址,所以须要有函数在点分十进制与32位地址这两种形式间进行转换。
# include < sys/socket.h> # 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);
描述:
例程:
#include<stdio.h> #include<arpa/inet.h> int main() { unsigned long addr = inet_addr("192.168.0.100");//将点分十进制转换为32bit地址 printf("addr = %u\n",htonl(addr)); struct in_addr ipaddr; ipaddr.s_addr = addr; printf("ipaddr = %s\n",inet_ntoa(ipaddr)); //网络字节序地址转换为点分十>进制 return 0; }
输出:
addr = 3232235620
ipaddr = 192.168.0.100
套接字类型主要有三种: