Socket编程(2)-Socket抽象机制

1 Socket API简介

1.1 最初设计

最初设计是基于BSD UNIX-Berkley,面向TCP/IP协议栈的接口。经过后续的发展,已经可以面向多个协议栈。Socket API也是事实上的工业标准,绝大多数的操作系统都支持,主流的操作系统如Windows和Linux都是支持的。Windows和Linux操作系统下Socket API的功能是有重叠的,基本编程思路不变,只需改动极小量的代码即可在相应操作系统编译、链接、运行。

1.2 形象比喻

首先,Socket API是Internet网络应用最典型的API接口,使用的通信模型为客户/服务器模型(C/S),这类模型描述了应用进程间通信的抽象机制。
我们可以将socket形象比喻成插头与插座,现在你想要给自己的手机充电,需要什么东西才能通过插座给手机充电呢?那就是适配手机的充电线和充电插头,在此我们把它们看成一个整体,叫做充电工具。现在你只需要将充电工具的USB插口一端与手机连接,另一端插头插到插座上,手机就能够进行充电,我们无须了解插座后面的电路构造,只要将插头插入插座就能使用充电功能,这就是API的现实体现。

1.3 通信定位

在一台主机上可能运行多个进程,比如现在打开的Web应用或者QQ,假设突然有个套接字要过来和你的进程通信,那现在主机上那么多进程,它应该和哪个进程通信?换句话说,它应该如何找到指定的进程进行通信?再形象点,插头要插哪个插座上?我们要如何准确定位服务器端的套接字呢?
其实很简单,在某一特定网络中,一台主机对应唯一的IP地址,服务器其实也是网络上的一台主机,也对应一个IP地址,这其实就能找到主机的地址。以五层模型为参考,主机间应用层的交互实际上是通过底层传输层协议来进行交互,操作系统需要提供端口来给进程,即端口号。
对外(主机与主机间)来说,套接字通过IP地址+端口号来标识通信端点,这样的标识是唯一的。对内(主机本身)来说,操作系统使用套接字描述符(socket descriptor)来管理套接字,大小一般是小整数。由此可见,套接字对内对外管理是不一样的。

  • 需要标识通信端点(对外):IP地址+Port端口号→套接字的端点地址
    (1)IP地址标识互联网中的机器地址。
    (2)Port端口号为16位整数,标识某一具体机器的进程,绑定套接字。
  • 操作系统/进程管理套接字(对内):使用套接字描述符(socket descriptor)。

2 socket抽象

2.1 socket创建

  1. 在Unix、Linux操作系统中,将socket看作文件。
  2. 当应用进程创建套接字时,操作系统分配一个数据结构存储该套接字相关信息。
  3. 返回套接字描述符。

2.2 socket管理

每个进程管理一个socket描述符表,表中的入口都有一个指针,指向所存储的数据结构。

socket描述符表 socket数据结构
[0] struct sockaddr_in *
[1] 其他数据结构
[2] 其他数据结构
... 其他数据结构

作为套接字最重要的信息就是套接字的地址信息,使用前需要指定本地的端点地址和远程的端点地址。使用TCP/IP协议簇的网络应用程序声明端点地址变量时,通过结构sockaddr_in来描述地址信息,使用前需要include

struct sockaddr_in{
    u_char sin_len;       // 地址长度
    u_char sin_family;    // 地址族(TCP/IP:AF_INET) 面向各种不同的协议栈,主要是TCP
    u_short sin_port;    // 端口号
    struct in_addr sin_addr;    // IP地址
    char sin_zero[8];    // 未用(置0)  填充0以保持与sockaddr结构的长度相同
}

不同地址族(协议栈)的端点地址是不一样的,TCP/IP协议簇的端点地址为IP+Port,通常指定其sin_family数据成员为AF_INET符号常量,表示本身为TCP/IP协议簇。

你可能感兴趣的:(Socket编程(2)-Socket抽象机制)