• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2023-08-19 19:40 Aet 隐藏边栏 |   抢沙发  11 
文章评分 2 次,平均分 5.0

UNIX-LINUX套接字描述符

  1. 套接字描述符是一个整数值,用于唯一标识进程中的一个开放的网络连接或者套接字
    1. UNIXLinux系统中,套接字描述符是一种特殊类型的文件描述符,可以用于表示打开的文件、管道、设备或者网络连接
  2. 套接字描述符唯一标识了进程中的一个网络连接
    1. 在创建新的套接字(例如通过socket函数)时,将返回一个新的描述符
  3. 可以使用像readwritesendrecv等函数来通过套接字描述符读取或写入数据。这些函数的工作方式与文件描述符非常相似
  4. 可以使用如setsockoptgetsockopt等函数来查询或修改与套接字描述符相关联的各种选项和参数
  5. 可以使用像selectpoll等函数,通过套接字描述符来同时监视多个网络连接的状态
  6. 当连接不再需要时,可以使用close函数来关闭套接字描述符,从而终止网络连接

WINDOWS套接字描述符

  1. Windows中,套接字由一个称为“句柄”的特殊对象表示,而不是一个整数
    1. 句柄用于引用系统内核中的对象,包括文件、线程、进程和窗口,以及套接字
    2. 套接字句柄与文件句柄不共享同一命名空间,并且不能用标准文件操作函数进行操作
  2. Windows中的套接字操作使用特定于WindowsWinsock API进行
    1. API提供了与BSD套接字相似的接口,但是使用了特定于Windows的数据类型和函数
  3. 区别于Linux
    1. Windows中创建套接字并返回句柄,而在Linux中创建套接字并返回一个整数描述符
    2. Windows中使用Winsock API的函数(如sendrecv)进行网络I/O,而在Linux中可以使用通用的文件I/O函数(如readwrite
    3. Windows中关闭套接字使用closesocket函数,而在Linux中使用通用的close函数

socket

概述

  1. 用于创建一个新的套接字,并返回一个套接字描述符
    1. 套接字是进行网络通信的端点,可以用于创建TCPUDP连接

原型

参数

  1. 套接字所使用的地址域(或协议族)。常见的值有:
    1. AF_INETIPv4协议族
    2. AF_INET6IPv6协议族
    3. AF_UNIX:本地套接字(用于进程间通信)
  2. 套接字的类型。主要选项有:
    1. SOCK_STREAM:流式套接字,用于TCP连接。
    2. SOCK_DGRAM:数据报套接字,用于UDP连接。
    3. 其他一些特殊类型,如SOCK_RAW用于创建原始套接字
  3. 特定协议的编号,通常与type参数相对应。常见的值有:
    1. 如果typeSOCK_STREAMprotocol通常设置为IPPROTO_TCP
    2. 如果typeSOCK_DGRAMprotocol通常设置为IPPROTO_UDP
    3. 在许多情况下,可以简单地将protocol设置为0,系统将自动选择与type相匹配的协议

返回值

  1. 成功时,socket函数返回一个非负整数,代表新创建的套接字描述符
  2. 失败时,返回-1,并设置相应的错误代码

示例

注意事项

  1. 创建的套接字描述符最初是“未绑定”的,即没有分配本地地址
    1. 通常,接下来需要使用bind函数将套接字绑定到一个特定的地址和端口
  2. 对于TCP套接字,还需要调用listenaccept函数来接受新的连接,或使用connect函数主动连接到远程端点
  3. 创建套接字后,还可以使用各种套接字选项来进一步自定义其行为,例如通过setsockopt函数

bind

概述

  1. 用于将套接字与特定的IP地址和端口号绑定
  2. 这个操作在创建服务器套接字并开始侦听客户端连接之前是必要的

原型

参数

  1. 套接字描述符,由socket函数返回
  2. 指向结构体sockaddr的指针,包含要绑定的IP地址和端口号
  3. addr指向的地址结构体的大小

返回值

  1. 成功时,返回0
  2. 失败时,返回-1,并设置errno以指示发生了什么错误

示例

  1. 这个示例中,使用INADDR_ANY绑定到服务器上所有可用的接口
    1. 如果你想绑定到特定的IP地址,你可以使用诸如inet_pton之类的函数来转换它

注意事项

  1. bind函数只能在套接字上调用一次
  2. 如果端口号已被其他进程使用,bind调用将失败
  3. 在服务器套接字上,bind通常后跟listen调用,以便开始接受连接

listen

概述

  1. 用于将未连接的套接字转换为被动套接字
    1. 表示内核应接受到此套接字的传入连接请求
    2. 通常用于服务器编程,用于准备接受客户端连接

原型

参数

  1. 已绑定(通过bind函数)未连接的套接字描述符
  2. 未完成连接队列的最大长度
    1. 这指定了内核应该为特定套接字排队的最大挂起连接数

返回值

  1. 成功时,返回0
  2. 失败时,返回-1,并设置errno以指示发生了什么错误

示例

注意事项

  1. listen函数不会返回新连接;它只准备套接字以接受它们
    1. 使用accept函数来实际接受连接
  2. backlog参数是指定系统允许排队的最大挂起连接数
    1. 这不包括已经接受但尚未由进程获取的连接。如果连接到达并且挂起队列已满,则客户端可能会收到错误
  3. 一旦调用了listen,套接字就不能用于发起连接,只能用来接受它们

accept

概述

  1. 用于接受一个到达的客户端连接请求
  2. 在服务器端的编程中,accept通常与bindlisten一起使用,以便设置服务器并等待并处理客户端的连接请求

原型

参数

  1. 一个已经绑定并处于监听状态的套接字描述符
  2. 一个结构,用于存储被接受的连接的客户端地址信息
  3. 一个指向整数的指针,该整数包含客户端地址结构的大小

返回值

  1. 成功时,返回一个新的套接字描述符,该描述符代表与客户端的新连接
    1. 所有的通信都应该通过这个新的描述符进行
  2. 失败时,返回-1,并设置errno以指示发生了什么错误

示例

注意事项

  1. accept函数可能会被阻塞,如果没有连接请求到达
    1. 可以通过将套接字设置为非阻塞或使用诸如selectpoll之类的函数来避免这种情况
  2. 返回的新套接字描述符与原始监听套接字描述符分开,有其自己的缓冲区、协议状态等
    1. 新描述符用于与特定客户端通信,而监听描述符继续用于接受新的连接请求
  3. 通常,每个连接请求都会生成一个新的套接字描述符
    1. 因此,服务器可能会同时管理多个连接
  4. 你可以通过addr参数获取到连接客户端的地址信息,例如 IP 地址和端口号

recv

概述

  1. 用于从已连接的套接字接收数据
    1. 该函数通常在 TCP 客户端和服务器编程中使用

原型

参数

  1. 已连接的套接字描述符
  2. 缓冲区,用于存储接收到的数据
  3. buf 缓冲区的大小(字节数)
  4. 接收操作的选项标志
    1. 例如 MSG_PEEKMSG_OOB 等。通常可以设置为0

返回值

  1. 成功时,返回接收到的字节数。如果连接已关闭,则返回0
  2. 失败时,返回-1,并设置errno以指示发生了什么错误

示例

注意事项

  1. recv 函数可能会被阻塞,如果没有数据可读
    1. 可以通过将套接字设置为非阻塞或使用诸如 selectpoll 之类的函数来避免这种情况
  2. 如果缓冲区小于接收的数据大小,则多余的数据会被丢弃
  3. 如果设置了 MSG_PEEK 标志,那么数据会被复制到缓冲区,但不会从输入队列中移除,所以下一次调用 recv 时还可以读到同样的数据

recv与接收缓冲区

  1. recv用于从套接字中接收数据,其工作方式与底层的接收缓冲区(Receive Buffer)紧密相关
    1. 接收缓冲区是TCP/IP协议栈中的一个关键组成部分

send

概述

  1. 用于通过已连接的套接字发送数据
    1. 它通常用于 TCP `客户端和服务器编程

原型

参数

  1. 已连接的套接字描述符
  2. 包含要发送数据的缓冲区
  3. 要发送的字节数
  4. 发送操作的选项标志
    1. 例如 MSG_NOSIGNALMSG_OOB 等。通常可以设置为0

返回值

  1. 成功时,返回实际发送的字节数
  2. 失败时,返回-1,并设置 errno 以指示发生了什么错误

示例

注意事项

  1. send 函数可能会被阻塞
    1. 如果套接字的发送缓冲区满了。可以通过将套接字设置为非阻塞或使用诸如 selectpoll 之类的函数来避免这种情况
  2. 返回的字节数可能小于要发送的字节数,特别是在非阻塞模式下
    1. 在这种情况下,应用程序应该再次尝试发送剩余的数据
  3. 如果设置了 MSG_OOB 标志,则发送的数据会被视为"带外"数据
    1. 带外数据是一种紧急机制,允许在正常数据流之外发送额外的信息
  4. 发送数据的成功并不意味着接收方已经收到了数据
    1. TCP 提供了可靠传输,但确认接收是在较低的协议级别处理的

send与发送缓冲区

  1. send函数用于将数据发送到套接字连接的另一端,其工作方式与发送缓冲区(Send Buffer)紧密相关
    1. 发送缓冲区在TCP/IP协议栈中起着重要的作用

connect

概述

  1. 这个函数是在客户端用来与服务器建立连接的
    1. 它尝试建立与指定的远程主机和端口的连接

原型

参数

  1. 套接字描述符,由 socket 函数返回
  2. 指向一个 sockaddr 结构的指针,该结构包含了你想连接的远程地址和端口
  3. addr所指向的结构的大小,通常设置为sizeof(struct sockaddr)

返回值

  1. 成功时返回0
  2. 失败时返回-1,并设置 errno 来表示错误类型

详细

  1. 当你调用 connect 时,系统会执行 TCP 的三次握手过程,并将套接字从 CLOSED 状态移动到 ESTABLISHED 状态(如果是 TCP 套接字)
    1. 一旦连接建立成功,你就可以使用 sendrecv 函数来发送和接收数据了
  2. connect 也可以用于 UDP,尽管 UDP 是无连接的
    1. UDP 的情况下,connect 不会尝试建立连接,但会将套接字与特定的远程地址和端口关联起来
    2. 可以使用 sendrecv(而不是 sendtorecvfrom)与那个特定的远程主机通信
    3. 当使用 connect 关联了远程地址和端口之后,你就不需要再使用 sendtorecvfrom 来指定这些细节了
  3. 在非阻塞模式下,connect也可以异步工作
    1. 它可能会立即返回,在连接尚未建立时你可以继续执行其他任务
    2. 你可以使用select, poll或其他机制来检测连接何时完成

示例

注意事项

  1. 对于无连接的协议(例如UDP),connect也有用处
  2. 虽然UDP本身不需要连接,但你可以通过调用connectUDP套接字指定默认的目的地址
    1. 这样,在以后的sendrecv调用中就不需要重复指定目的地址

sendto

概述

  1. 用于无连接的数据报协议(例如UDP),用于向指定的目的地址发送数据
  2. send函数不同,sendto允许你每次发送时指定不同的目的地址

原型

参数

  1. 套接字描述符,表示你想通过哪个套接字发送数据
  2. 指向你想发送的数据的指针
  3. 你想发送的字节数
  4. 可选的发送标志,通常可以设置为0
  5. 指向一个sockaddr结构的指针,其中包含你想发送数据的目的地址和端口
  6. dest_addr所指向的结构的大小,通常设置为sizeof(struct sockaddr)

返回值

  1. 返回值是实际发送的字节数
  2. 如果出现错误则返回-1,可以通过errno来检查具体错误

示例

注意事项

  1. sendto函数使得你可以轻松地向不同的目的地发送数据报,无需每次都更改套接字的“连接”状态或使用不同的套接字
    1. 这对于实现各种无连接的网络协议非常有用

recvfrom

概述

  1. 用于在无连接的数据报协议(例如 UDP)上接收数据
    1. 该函数接收数据报并捕获数据报的来源地址

原型

参数

  1. 套接字描述符,标识你希望从哪个套接字接收数据
  2. 指向一个缓冲区的指针,其中将存储接收到的数据
  3. 缓冲区的大小,即你想接收的最大字节数
  4. 接收标志,通常可以设置为0
  5. 指向一个 sockaddr 结构的指针,用于保存发送方的地址信息
  6. 输入/输出参数
    1. 调用 recvfrom 时,你必须设置它为 src_addr 所指向的结构的大小
    2. recvfrom 返回时,该值将被设置为实际地址的大小

返回值

  1. 返回值是实际接收的字节数
  2. 如果出现错误则返回 -1,并可以通过 errno 来检查具体错误

示例

  1. 创建了一个UDP套接字,并绑定到端口8000
    1. 然后,它使用 recvfrom 函数接收一个数据报,并打印接收到的内容和来源地址

接收缓冲区

定义

  1. 接收缓冲区是一块内核分配的内存区域,用于暂存从网络接收但尚未被应用程序读取的数据

大小

  1. 缓冲区的大小对性能有重要影响,太小可能导致阻塞,太大可能浪费内存
    1. 许多操作系统允许动态调整缓冲区大小,并可能具有自动调整机制

数据流入

  1. TCP数据包到达,并且通过TCP的各种检查后(例如序列号检查、校验和验证等),数据会被复制到接收缓冲区
  2. 如果缓冲区已满,新的数据包可能会被丢弃,TCP的流量控制机制会通知发送方减慢发送速率

应用程序读取

  1. 当应用程序调用recv函数来读取数据时,数据会从接收缓冲区复制到应用程序指定的内存位置
  2. 如果缓冲区为空,recv的行为取决于套接字是否设置为阻塞模式
    1. 在阻塞模式下,recv会等待数据到来
    2. 在非阻塞模式下,recv会立即返回一个错误

流量控制

  1. 接收缓冲区的大小和使用情况是TCP流量控制的关键因素之一
  2. TCP窗口大小通常与接收缓冲区的剩余空间有关
    1. 如果接收缓冲区满了,窗口大小可能会缩小,从而通知发送方减慢发送速率

缓冲区调整

  1. 操作系统通常允许通过套接字选项(例如SO_RCVBUF)调整接收缓冲区的大小
    1. 在高性能的网络应用中,合理调整缓冲区大小可能有助于优化性能

与阻塞和超时的交互

  1. recv函数的行为还可能受到与套接字关联的阻塞模式和超时设置的影响
    1. 例如,可以设置recv的超时,以避免长时间等待缓冲区中的数据

与其他接收选项的交互

  1. recv函数还支持一些标志
    1. 例如MSG_PEEK,允许应用程序在不实际删除数据的情况下检查接收缓冲区的内容

发送缓冲区

定义

  1. 发送缓冲区是一块内核分配的内存区域,用于暂存由应用程序发送但尚未被TCP协议栈发送到网络的数据

大小

  1. 缓冲区的大小对性能和资源使用有关键影响,通常可以通过套接字选项(例如SO_SNDBUF)进行调整

数据流出

  1. 当应用程序调用send函数发送数据时,数据会被复制到发送缓冲区
  2. 如果缓冲区已满,send的行为取决于套接字是否设置为阻塞模式
    1. 在阻塞模式下,send会等待缓冲区有空间
    2. 在非阻塞模式下,send会立即返回一个错误

TCP协议的交互

  1. TCP协议栈会逐渐将数据从发送缓冲区发送到网络
  2. 发送过程受到TCP的流量控制、拥塞控制和可靠传输机制的影响
    1. 例如,如果接收端的接收缓冲区满了,发送方可能会暂停发送

确认与重传

  1. TCP连接中,发送的数据需要得到接收端的确认。
  2. 确认的数据会从发送缓冲区中移除
    1. 如果某些数据未得到确认,可能会触发TCP的重传机制,数据将从发送缓冲区重新发送

缓冲区调整与优化

  1. 在某些情况下,可能需要调整发送缓冲区的大小以适应特定的网络条件或应用需求
    1. 合理的缓冲区大小可以帮助确保高效的网络利用,而不是浪费带宽或内存

与其他发送选项的交互

  1. send函数支持一些标志
    1. 例如MSG_DONTROUTE,这些标志可能会影响发送缓冲区如何与底层的TCP协议栈交互

与应用程序的交互

  1. 发送缓冲区的状态可能会影响应用程序的性能和行为
    1. 例如,一个满的发送缓冲区可能会导致应用程序阻塞
    2. 而一个空的发送缓冲区可能会触发应用程序继续发送更多数据

函数理解解析

套接字队列

  1. 对于面向连接的套接字(例如,TCP套接字),操作系统通常为每个套接字(socket)维护了两个队列:
    1. 已完成连接的队列
    2. 未完成连接的队列

已完成连接的队列

  1. 当三次握手完成并成功建立连接后,这些连接会被放在已完成连接的队列中
    1. 它们已经完成了TCP三次握手并成功地建立了一个连接

未完成连接的队列

  1. 当一个客户端尝试连接到服务器,但是三次握手还没有完成,这些连接会被放在未完成连接的队列中
    1. 例如,如果已经发送了SYN包,但还没有收到客户端的ACK包,这种连接就会在这个队列中

listen的backlog

  1. 这个参数定义了操作系统应该为特定套接字队列的最大长度
    1. 具体来说,它指的是已完成连接的队列的最大长度
    2. 换句话就是,这个参数指定了操作系统为这个套接字维护的所谓已完成的连接的队列的最大数量
    3. 而未完成连接队列(也叫半连接队列),它的大小通常与这个参数无关,它仅用于存放处于三次握手过程中的连接请求
  2. 注意:
    1. 根据操作系统的实现,实际的队列长度可能会受到系统级别限制,或者可能考虑到未完成连接的队列
    2. 也就是说,backlog 参数只是一个请求值,操作系统可能会选择使用这个值,也可能会对其进行调整
      例如,有些系统可能会将实际的队列长度设置为 backlog 参数的两倍
  3. 当有客户端尝试连接并且已完成连接的队列已满时,新的连接请求可能会被拒绝
    1. 同样,如果未完成连接的队列已满,后续的SYN请求也可能被丢弃
  4. 当服务器调用 accept 函数时,它会从已完成连接的队列中取出一个连接
    1. 如果这个队列为空,根据套接字的阻塞模式,accept 要么阻塞,要么立即返回一个错误

发送(接收)缓冲区是为每个套接字维护了一个么

  1. 操作系统为每个套接字维护了一个发送缓冲区和一个接收缓冲区
  2. 这两个缓冲区存在于内核
    1. 应用程序调用send时,数据会从应用程序的用户空间复制到内核空间的发送缓冲区
      然后,操作系统的网络协议栈会从发送缓冲区获取数据并将其发送到网络
    2. 当数据从网络到达时,它会首先被放入内核空间的接收缓冲区
      然后,应用程序通过调用recv等函数从接收缓冲区中读取数据,此时数据会被复制到用户空间

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享