对Socket基本用法的复习和理解

对Socket基本用法的复习和理解

前言

因为工作中对Socket的使用不多,偶尔需要用到的时候容易想不起来,因此在这次实现需求的时候特地做了一些笔记,简单整理后发到blog上,一方面是也许可以帮助到需要的人,另一方面也是如果有误,大家也可以提出意见帮助自己进步。

bind函数

在Server,bind函数用于将socket绑定到本地IP并开始监听。

在客户端,不需要用bind,一般用connect,然后OS会自行选择合适的端口。

IP+Port唯一标识网络通讯中的一个线程

地址结构

inet_pton和inet_ntop是两个IP地址转换函数,inet_pton把地址从 点分十进制 转换为 整数, inet_ntop则相反,把地址从 整数 转换为 点分十进制表示。

p是presentation的缩写,n是network的缩写

为了向前兼容,很多 socketaddr 退化成了 void*,只传一个地址给函数,函数在内部进行转换。

socketaddr : 是通用的套接字结构,可以在不同的协议族之间强转;

sockeaddr_in : 以太网中用的套接字结构,出现是因为前者不好用。

因为两者大小一致,数据也兼容,而后者比较好用,所以一般用后者配置地址,然后强制转换为前者,这种操作不会有任何副作用。

两个结构体在内存布局上是兼容的,这是有意设计的结果

常见的套接字类型

SOCK_STREAM

SOCK_STREAM代表 按顺序的、可靠的、数据完整的基于字节流的连接,基于TCP。

要怎么理解这些描述呢?

按顺序的:即数据以发送的顺序到达接收方。否则就是乱序,乱序下发送片段1、2、3,可能以1、3、2的顺序收到。

可靠的:发送到数据包会被确认接收,未被确认的数据包将被重发,直到收到确认。

数据完整的:数据不会被截断、重复或丢失,TCP会进行错误检测和校验。

基于字节流:数据以字节流(byte stream)的形式发送和接收,应用程序可以以任意大小的数据块来读写数据,这和面向消息的传输方式是不同的(SOCK_DGRAM、UDP)。

SOCK_STREAM也是面向连接的。何为面向连接?指的是正式通信前要先确定通信路径,若路径被破坏会重新建立。

可靠性和顺序传递并不冲突。顺序性体现在若某个包(如包2)丢失或延迟,接收方不会把后续的包传给应用层(如包3)。可靠性体现在ACK机制和重传机制。

实际上,TCP使用了滑动窗口协议和累计确认(为了提升传输效率)。

滑动窗口允许发送方在等待确认的时候发送多个数据包(窗口大小确定能发送的数量)。

累计确认简单来说就是发送ACK确认最后收到的顺序数据包,如发送 1、2、3、4,收到了1、2、3,就回复ACK 3,代表需要重发包4。

SOCK_DGRAM

无连接、不保证可靠、基于消息的通信,因此开销低,更适合实时应用,如直播。

无连接: 不像SOCK_STREAM需要三次握手建立连接,所以传输效率高。

不保证可靠:可能丢失、乱序、重复。

基于消息(数据报):数据以数据报的形式发送,保留消息完整性。

开销低:因为不用管理连接和保证可靠。

无连接,即每个数据包都可能走不同的路径,因此数据包到达的先后次序和到达与否都很难保证。

每个数据报是一个独立的消息,有固定的长度和边界。数据报是网络传输中的独立单元,是传输层概念。消息是信息传递的单元,可以由多个数据报组成,是应用层概念。

这里我觉得容易混杂的是将传输层的消息和应用层的消息混为一谈,SOCK_DGRAM所说的消息是传输层的消息,也就是数据报,一个数据报就是一个消息,和应用层的可能由多个数据报组成的消息不同。两个消息有概念上的相同点,需要注意。

SOCK_STREAM、SOCK_DGRAM 和 TCP、UDP 的关系

SOCK_STREAM、SOCK_DGRAM是套接字类型,TCP、UDP是传输层协议;

SOCK_STREAM实际上用TCP协议来实现,同样地,SOCK_DGRAM基于UDP实现。

SOCK_SEQPACKET

特点:

面向连接

基于数据包:每个数据包是一个完整的消息

可靠性

顺序性

因为提供了安全的数据包传输,适合用在对安全要求高的场景,如发送账户信息。

和SOCK_STREAM的异同:

都面向连接

都可靠

都保证顺序

SOCK_STREAM以字节流传输数据,没有明确的消息边界,应用层的数据可以是任意大小的,底层会拆分;SOCK_SEQPACKET以数据包传输数据,每个包是一个完整消息,有明确边界。

在不同的系统上,SOCK_SEQPACKET会采用不同的底层协议来实现,如Linux会用SCTP。

SOCK_RAW

特点:

原始:提供了对网络层协议(IP)、传输层协议(TCP、UDP)的原始访问

完全控制:允许用户在低层次操作,如直接构造、解析IP数据报

无处理: 不会对数据报进行任何额外处理,如校验,可以直接操作协议头

因为暴露了底层,适用于自定义协议的实现。

SOCK_RDM

无连接、可靠(可靠送达),但不完全保证数据的完整性,保留了数据报的特性。

为什么可靠却不完整?可靠性分为多种,包括但不限于数据完整可靠性、数据传输可靠性等。这里的可靠性指的是在传输中可靠送达,不会丢失。

数据完整性指的是接收的数据和发送的数据完全一致,因为SOCK_RDM不是面向连接的,自然无法保证数据包的顺序,也就无法保证数据完整性。需要注意的是,虽然SOCK_RDM没有保证数据完整,但还是可以采用一些别的措施来提高数据完整性的。例:因为数据包一定会被送达,发送方可以给数据包编号,然后在接收方重组,实现更高程度的数据完整。

此外,如果在传输过程中出现了传输错误导致数据报出错,SOCK_RDM也不会进行校验和重传(自然也可以自己增加校验来预防)。

因此SOCK_RDM是保证送达,但不保证顺序和正确性,适用于数据采集场景。

SOCK_DCCP

基于DCCP协议、可靠、有序,适用于实时应用。

SOCK_PACKET

适用于与物理设备交互,用于对网络数据包进行深入分析的场景。

SOCK_CLOEXEC

进程调用exec()的时候会自动关闭socket,适用于多线程编程。

SOCK_NONBLOCK

非阻塞,即无数据可读时,不会阻塞而是直接返回。

通信流程

以TCP为例,简要说明通信流程和用到的函数。

客户端与服务器通信的简要流程

bind函数因为参数addr的长度不定,所以有参数addr_len。

标志INADDR_ANY表示在多张网卡的所有地址上监听。

int listen( int sockfd, int backlog)的第二个参数backlog代表连接队列的长度。连接状态分为半连接和全连接,半连接是服务器已经收到了客户端的连接请求,但还没有完成三次握手;全连接是完成了三次握手,可以正常传输数据。如果新连接请求到达,而连接队列中处于全连接和半连接的连接数量已经达到了backlog,服务器不会接受这个请求,而是回复拒绝后直接丢弃。

相关推荐

Lenovo笔记本电脑的电源开关按键在什么位置
假的网站365怎么看

Lenovo笔记本电脑的电源开关按键在什么位置

06-28 👁️ 1104
GT820 显卡性能深度剖析:真实等级与适用环境全揭秘
中国的365体育投注

GT820 显卡性能深度剖析:真实等级与适用环境全揭秘

06-29 👁️ 7983
什么修改器最好用 游戏修改器排行榜第一名
网上注册送365的平台

什么修改器最好用 游戏修改器排行榜第一名

06-27 👁️ 7617