网络编程相关函数深层次解析

2024-05-07 07:48

本文主要是介绍网络编程相关函数深层次解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

connect函数解析

TCP客户用connect函数来建立与TCP服务器的连接:

#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr* servaddr, socklen_t addrlen);
//成功返回0,失败返回-1并设置errno

客户端在调用connect之前不必非得调用bind函数,因为如果需要的话内核会确定源IP地址并选择一个临时端口号作为端口;

如果是TCP套接字,调用connect函数将触发TCP的三次握手过程,而且仅在连接建立成功或出错才返回:

  • 若TCP没有收到SYN分节的响应,则返回ETIMEOUT错误。举例,调用connect函数时,4.4BSD内核发送一个SYN,若无响应则等待6s后再发送一个,若仍无响应则等待24s后再发送一个。若总共等待了75s后仍未收到响应则返回本错误。

  • 若对客户的SYN的相应是RST(表示复位),则表明该服务器主机在我们指定的端口上没有进程在等待与之连接。这是一种硬错误,客户一收到RST就马上返回ECONNERFUSED错误;

  • 若客户发出的SYN在中间某个路由器上引发一个“destination unreachable”(目的地不可达)ICMP错误,则认为是一个软错误。客户主机内核会保存该消息,并按第一种情况所述的时间间隔继续发送SYN,若在某个规定时间内仍无响应,则把保存的信息(ICMP错误)作为EHOSTUNREACH或ENETUNREACH错误返回给进程,以下两种情况是可能的:

    • 按照本地系统的转发表,根本没有到达远程系统的路径;
    • connect调用根本不等待就返回;

按照TCP状态转移图,connect函数导致当前套接字从CLOSED状态转移到SYN_SENT状态,若成功,则转移到ESTABLISHED状态。若connect失败,则该套接字不再可用,必须关闭,不能对这样的套接字再次调用connect函数;

listen函数解析

listen函数仅由TCP服务器调用,其做两件事:

  • 当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的客户套接字。listen函数把一个未连接的套接字转换为一个被动套接字,指示内核应该接受指向该套接字的连接请求。根据TCP状态转换图,调用listen导致套接字从CLOSED状态转换到LISTEN状态

  • listen函数的第二个参数规定了内核应该为相应套接字排队的最大连接个数:

    #include<sys/socket.h>int listen(int sockfd, int backlog);

为了理解其中的backlog参数,我们必须认识到内核为任何一个给定的监听套接字维护两个队列:

  • 未完成队列:每个这样的YSN分节对应其中一项:已由某个客户发出并到达服务器,而服务器正在等待完成相应的TCP三路握手,这些套接字处于SYN_RECV状态;
  • 已完成连接队列:每个已完成的TCP三路握手过程的客户对应其中的一项,这些套接字处于ESTABLISHED状态;

每当在未完成连接队列中创建一项时,来自监听套接字的参数就复制到即将建立的连接中,连接的创建机制是完全自动的。

  • 当来自客户的SYN到达时,TCP在未完成队列中创建一个新项,然后响应三路握手的第二个分节:服务器的SYN相应,其中捎带对可读SYN的ACK,这一项一直保留在文玩城连接队列中,直到三路握手的第三个分节(客户对服务器的SYN的ACK)到达,或者该项超时为止;

  • 如果三路握手成功,该项从未完成队列移到已完成队列的队尾,当进程调用accept时,已完成连接队列中的队头项将返回给进程,或者该队列为空,那么进程就被投入到睡眠,知道TCP在该队列中放入一项才唤醒它;

accept函数解析

函数原型为:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

如果已连接队列中没有等待的连接,套接字也没有被标记为non-blocking,accept()会阻塞调用函数直到连接出现,如果套接字被标记为non-blocking,队列中也没有等待的连接,accept()返回错误EAGAIN 或 EWOULDBLOCK

一般来说,实现时accept()为阻塞函数,当监听socket调用accept()时,它先到自己的receive_buf中查看是否有连接数据包:

  • 若有,把数据拷贝出来,删除接收到的数据报,创建新的socket与客户发来的地址建立连接;
  • 若没有,就阻塞等待;

考虑以下情况:如果监听队列中处于ESTABLISHED状态的连接对应的客户端出现网络异常(比如掉线),或者提前退出,那么服务器端对这个连接执行的accept调用是否成功?

accept只是从监听队列中取出连接,而不论连接处于何种状态(如上面的ESTABLISHED或者CLOSE_WAIT状态),更不关心任何网络状况的变化;

close关闭连接

函数原型是:int close(int fd);

fd参数是待关闭的连接,不过,close系统调用并非总是立即关闭一个连接,而是将fd的引用计数减1,只有当fd的引用计数为0时,才真正关闭连接。

如果无论如何都要立即终止连接(而不是将socket引用计数减1),可以使用shutdown系统调用:

#include<sys/socket.h>
int shutdown(int sockfd, int howto);

howto参数决定了shutdown的行为:

  • SHUT_RD:关闭sockfd上读的一半,应用程序不会再针对socket文件描述符执行读操作,并且将socket接收缓冲区的数据都丢弃;
  • SHUT_WR:关闭sockfd上写的一半,sockfd的发送缓冲区的数据会在真正关闭连接之前全部发送出去,应用程序不再对该sockfd执行写操作,连接处于半关闭状态;
  • SHUT_RDWR:同时关闭sockfd上的读和写;

带外标记

Linux内核检测到TCP紧急标志时,将通知应用程序由带外数据需要接收,内核通知应用程序带外数据到达有两种常见方式:

  • I/O复用产生的异常;
  • SIGURG信号;

但是,即使应用程序得知了有带外数据需要接收的通知,还需要知道带外数据在数据流中的具体位置,才能正确接收带外数据,可通过如下系统调用实现:

#include<sys/socket.h>
int sockatmark(int sockfd);

其判断sockfd是否处于带外标记,即下一个要被读取的数据是否是带外数据,如果是,sockatmark返回1,可以利用带MSG_OOB标志的recv调用来接收带外数据。否则,返回0;

socket选项

#include<sys/socket.h>
int getsockopt(int sockfd, int level, int option_name, void* option_value, socklen_t* restrict option_len);int setsockopt(int sockfd, int level, int option_name, const void* option_value, socklen_t option_len);

对服务器而言,有部分socket选项只能在调用listen系统调用前针对监听socket设置才有效,对监听socket设置这些选项,那么accept返回的连接socket将自动继承这些选项

  • socket选项的SO_REUSEADDR来强制使用被处于TIME_WAIT状态的连接占用的socket地址;

    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

  • SO_RCVBUF 和 SO_SNDBUF选项分别表示TCP缓冲区和发送缓冲区的大小,当我们用setsockopt设置TCP接收缓冲区和发送缓冲区的大小时,系统都会将其值加倍,并且不得小于某个最小值。TCP接收缓冲区最小值为256字节,发送缓冲区的最小值为2048字节,这样做确保一个TCP连接有足够的空闲缓冲区来处理拥塞;

   setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuf, sizeof(sendbuf));setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &recvbuf, sizeof(recvbuf));

这篇关于网络编程相关函数深层次解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/966758

相关文章

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

python常见环境管理工具超全解析

《python常见环境管理工具超全解析》在Python开发中,管理多个项目及其依赖项通常是一个挑战,下面:本文主要介绍python常见环境管理工具的相关资料,文中通过代码介绍的非常详细,需要的朋友... 目录1. conda2. pip3. uvuv 工具自动创建和管理环境的特点4. setup.py5.

全面解析HTML5中Checkbox标签

《全面解析HTML5中Checkbox标签》Checkbox是HTML5中非常重要的表单元素之一,通过合理使用其属性和样式自定义方法,可以为用户提供丰富多样的交互体验,这篇文章给大家介绍HTML5中C... 在html5中,Checkbox(复选框)是一种常用的表单元素,允许用户在一组选项中选择多个项目。本

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Python包管理工具核心指令uvx举例详细解析

《Python包管理工具核心指令uvx举例详细解析》:本文主要介绍Python包管理工具核心指令uvx的相关资料,uvx是uv工具链中用于临时运行Python命令行工具的高效执行器,依托Rust实... 目录一、uvx 的定位与核心功能二、uvx 的典型应用场景三、uvx 与传统工具对比四、uvx 的技术实

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

CSS3中的字体及相关属性详解

《CSS3中的字体及相关属性详解》:本文主要介绍了CSS3中的字体及相关属性,详细内容请阅读本文,希望能对你有所帮助... 字体网页字体的三个来源:用户机器上安装的字体,放心使用。保存在第三方网站上的字体,例如Typekit和Google,可以link标签链接到你的页面上。保存在你自己Web服务器上的字

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和