目录
tcp套接字编程使用套接字地址结构和函数与内核交互,最终由内核进行状态维护和协议族的层间交互。
在此介绍套接字地址结构只涉及IPV4。
套接字地址结构
套接字编程需要指定套接字的地址作为参数,不同的协议族有不同的地址结构定义方式。这些地址结构通常以 sockaddr_ 开头,每一个协议族有一个唯一的后缀,例如对于以太网IPV4,其结构名称为 sockaddr_in, IPV6为sockaddr_in6。
通用套接字数据结构
通用的套接字地址类型的定义如下,它可以在不同协议族之间进行强制转换。
typedef unsigned short sa_family_t ;
struct sockaddr /*套接字地址结构*/
{
sa_family_t sa_family; /*协议族*/
char sa_data[14]; /*协议族数据*/
};
上述结构中协议族成员变量 sa_family 的类型为 sa_family_t ,其实这个类型是 unsigned short 类型,因此成员变量 sa_famliy 的长度为2个字节,struct sockaddr结构的长度为16个字节。
实际使用的套接字数据结构
在网络程序设计中所使用的函数中儿乎所有的套接字函数都用这个结构作为参数,例如 bind()函数的原型为:
int bind(int sockfd, //套接字文件描述符
const struct sockaddr *my_addr, //套接字地址结构
socklen_t addrlen); //套接字地址结构的长度
但是使用结构 struct sockaddr 不方便进行设置,在以太网中,一般采用结构 struct sockaddr_in 进行设置,这个结构的定义如下
struct sockaddr_in //以太网套接字地址结构*/
{
u8 sin_len; /*结构 struct sockaddr_in 的长度,16*/
u8 sin_family; /*通常为 AF_INET*/
u16 sin_port; /*16位的端ロ号,网络字节序*/
struct in_addr sin_addr; /*IP 地址32位*/
char sin_zero[8];/*未用*/
};
//结构 struct sockaddr_in 的成员变量 in_addr 用于表示 IP 地址,这个结构的定义如下:
struct in_addr /*IP 地址结构*/
{
u32 s_addr; /*32位 IP 地址,网络字节序*/
};
由于结构 struct sockaddr 和结构 struct sockaddr_in 的大小是完全一致的,所以进行地址结构设置时,通常的方法是利用结构 struct sockaddr_in 进行设置,然后强制转换为结构 struct sockaddr 类型。因为这两个结构大小是完全一致的,所以进行这样的转换不会有副作用。
TCP网络编程架构
TCP 网络编程有两种模式,一种是服务器模式,另一种是客户端模式。
服务器模式创建一个服务程序,等待客户端用户的连接,接收到用户的连接请求后,根据用户的请求进行处理;
客户端模式则根据目的服务器的地址和端口进行连接,向服务器发送请求并对服务器的响应进行数据处理。
1. 服务器端的程序设计模式
流程主要分为套接字初始化(socket()函数),套接字与端口的绑定( bind()函数),设置服务器的侦听连接( listen()函数),接受客户端连接(accept()函数),接收和发送数据( read() 函数、 write()函数)并进行数据处理及处理完毕的套接字关闭( close()函数)。
socket(): 套接字初始化过程中,根据用户对套接字的需求来确定套接字的选项。这个过程中的函数为socket(),它按照用户定义的网络类型、协议类型和具体的协议标号等参数来定义。系统根据用户的需求生成一个套接字文件描述符供用户使用。
bind(): 套接字与端口的绑定过程中,将套接字与一个地址结构进行绑定。绑定之后,在进行网络程序设计的时候,套接字所代表的 IP 地址和端口地址,以及协议类型等参数按照绑定值进行操作。
listen(): 由于一个服务器需要满足多个客户端的连接请求,而服务器在某个时间仅能处理有限个数的客户端连接请求,所以服务器需要设置服务端排队队列的长度。服务器侦听连接会设置这个参数,限制客户端中等待服务器处理连接请求的队列长度。
accept(): 在客户端发送连接请求之后,服务器需要接收客户端的连接,然后才能进行其他的处理。
read()、write():在服务器接收客户端请求之后,可以从套接字文件描述符中读取数据或者向文件描述符发送数据。接收数据后服务器按照定义的规则对数据进行处理,并将结果
发送给客户端。
close():当服务器处理完数据,要结束与客户端的通信过程的时候,需要关闭套接字连接。
2. 客户端的程序设计模式
主要分为套接字初始化(socket() 函数),连接服务器( connect() 函数),读写网络数据( read()函数、 write()函数)并进行数据处理和最后的套接字关闭(close()函数)过程。
客户端程序设计模式流程与服务器端的处理模式流程类似,二者的不同之处是客户端在套接字初始化之后可以不进行地址绑定,而是直接连接服务器端。
客户端连接服务器的处理过程中,客户端根据用户设置的服务器地址、端口等参数与特定的服务器程序进行通信。
3.客户端与服务器的交互过程
客户端与服务器在连接、读写数据、关闭过程中有交互过程。
客户端的连接过程,对服务器端是接收过程,在这个过程中客户端与服务器进行三次握手, 建立 TCP 连接。建立 TCP 连接之后,客户端与服务器之间可以进行数据的交互。
客户端与服务器之间的数据交互是相对的过程,客户端的读数据过程对应了服务器端的写数据过程,客户端的写数据过程对应服务器的读数据过程。在服务器和客户端之间的数据交互完毕之后,关闭套接字连接。