接口同时选择地址族与通信语义

在Linux等提供BSD风格套接字的系统里,socket调用创建端点并返回文件描述符。地址族区分IPv4、IPv6、本地通信等体系,类型则区分字节流、数据报等语义,另可指定具体协议;它不是一个只接受IP地址的万能TCP连接函数。

同一套接口也能用于没有网络端口号的本地通信。文件描述符是进程引用内核对象的方式,不是写进报文的端口号,更不是跨设备稳定不变的会话标识。把这几层分开,才能解释共享、关闭和协议选择。

参考:[1] [2]

监听端点与接入后的端点分开

服务器通常把端点绑定到本地地址,用listen进入接受连接的状态,再通过accept取得新的已接入套接字。原监听端点继续承担接受其他连接的职责;客户端的connect则请求建立或关联相应远端,具体含义取决于所用协议。

绑定、建立连接和收发数据是不同步骤,也各自可能失败。非阻塞连接可先返回正在进行,程序之后根据就绪事件与错误状态确认结果;不能把创建了一个描述符,或看到了可写通知,就当成对方已经完成某项应用操作。

参考:[2]

流和数据报需要不同的读取方式

字节流套接字不保存应用每次write的边界,一次写入可能分多次读取,多次写入也可能在一次读取中出现。协议应另行定义长度、分隔符或其他成帧规则,而不能把网络读取次数当成消息个数。

数据报接口保有消息边界,但基本数据报语义不自动提供可靠、有序的交付。阻塞与非阻塞又是另一维度:非阻塞操作遇到暂时无法推进时返回相应状态,由程序等待或重试,并不会因此把网络延迟变成零或自动构造可靠协议。

参考:[1] [2]