计算机专业在大学里学习的网络课程里,留给大家印象最深刻的就是OSI的7层模型、TCP/IP的4层模型,讲到TCP,面试问最多就是建立连接的三次握手和断开连接的四次挥手。但在实际项目或编程应用中,这些理论知识似乎应用不上,我们只需要知道一些API就可以实现服务器、客户端的网络编程了。
Socket编程怎么和TCP的原理关联起来呢?怎么理解socket委托或者调用操作系统实现的TCP/IP协议栈做的具体工作呢?我觉得有必要结合具体的代码梳理这个流程,帮助程序员理解API背后的逻辑,对我们查找、解决问题应该会很有帮助。
首先介绍下基础理论知识:
TCP是属于第3层传输层的协议,IP是第2层网络层的协议,这是TCP/IP网络协议簇的最为核心的2个协议。不同的操作系统有自己的不同版本的网络协议栈的实现,总体上是上层委托或调用下层的协议来实现。
TCP/IP协议簇总体上分为4层,包含几十个协议,比如PPP、ARP、ICMP、RIP,可以参看下表:
比如处于网络接口层(第2层)的SLIP(串行线互联网协议),PPP(点到点协议),ARP(地址解析协议),RARP(反向地址解析协议);
层次 | 层次名称 | 协议 |
---|---|---|
第4层 | 应用层 | HTTP(超文本传输协议),SMTP(简单邮件传输协议),FTP(文件传输协议),DNS(域名系统),DHCP(动态主机配置协议) |
第3层 | 传输层 | TCP(传输控制协议),UDP(用户数据报协议) |
第2层 | 网络层 | ARP(地址解析协议),IP(网际协议),IPsec(iP安全性),ICMP(互联网控制报文协议), |
第1层 | 网络接口层 | SLIP(串行线互联网协议),PPP(点到点协议) |
TCP全称为传输控制协议,它创建和管理设备之间的连接,并在使用IP时确保可靠的、具有流量控制的数据交付。
一、socket地址结构
// IPv4的Socket地址结构
struct in_addr{
in_addr_t s_addr; // 32 位 IP 地址,网络字节序
};
struct sockaddr_in{
uint8_t sin_len;//IPv4 为固定的 16 字节长度
sa_family_t sin_family; //地址簇类型,为 AF_INET
in_port_t sin_port; //16 位端口号,网络字节序
struct in_addr sin_addr; // 32 位 IP 地址
char sin_zero[8]; //未用
};
// 通用的socket地址结构
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[4];
};
对服务器来说,需要绑定端口,为客户端连接提供服务。需要有以下几个步骤:
1.创建套接字
int socket(int domain, int type, int protocol);
函数返回socket描述符,用以标识本机的不同网络连接,操作系统将socket视为一种资源文件,Linux下打开文件数目不同用户是有不同限制的,有时候服务器遇到连接数受限问题,可以查查这方面的问题。
domain参数一般取AF_INET
type:表示套接字类型,SOCK_STREAM表示是TCP,SOCK_DGRAM表示UDP
protocol:表示协议,一般设为0
当调用这个函数后,应用程序会得到可以控制socket的描述符,协议栈申请内存空间,用于存储维持连接或发送数据报需要的控制信息
2. 绑定端口
int bind(int sockfd, struct sockaddr *sa, int addrlen);