Linux网络编程 | socket选项设定 及 网络信息API

文章目录

  • 读取和设置 socket 选项
    • SO_REUSEADDR
    • SO_RCVBUF 和 SO_SNDBUF
    • SO_RCVLOWAT 和 SO_SNDLOWAT
    • SO_LINGER 选项
  • 网络信息API
    • gethostbyname 和 gethostbyaddr
    • getservbyname 和 getservbyport
    • getaddrinfo
    • getnameinfo


读取和设置 socket 选项

正如 fcntl 系统调用是控制文件描述符属性的通用 POSIX 方法;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, void* option_value, socklen_t* restrict option_len);
// sockfd 指定被操作的socket。
// level 指定操作哪个协议的选项(属性),如:IPv4、IPv6、TCP等。
// option_name 指定选项的名字。
// option_value 和 option_len 参数分别指定操作选项值和长度。
// 成功返回0,失败返回-1并置errno。
socket 选项
leveloption数据类型说明必须在 listen/connect 调用之前设置
SOL_SOCKETSO_DEBUGint打开调试信息YES
(通用 socket 选项,与协议无关)SO_REUSEADDRint重用本地地址。如:可以令服务器处于 TIME_WAIT 的端口立刻被使用。
SO_TYPEint获取 socket 类型
SO_ERRORint获取并清除 socket 错误状态
SO_DONTROUTEint不查看路由表,直接将数据发送给本地局域网内的主机。类同 send 系统调用的 MSG_DONTROUTE。YES
SO_RCVBUFintTCP接收缓冲区大小(最小值是256字节)YES
SO_SNDBUFintTCP发送缓冲区大小(最小值是2048字节)YES
SO_RCVLOWATintTCP接收缓冲区低水位标记YES
SO_SNDLOWATintTCP发送缓冲区低水位标记YES
SO_RCVLOWATint接收数据超时
SO_SNDLOWATint发送数据超时
SO_KEEPALIVEint发送周期性保活报文以维持连接YES
SO_OBBINLINEint接收到的带外数据将 在线存留 在普通数据的输入队列中,此时我们不能使用带 MSG_OOB 的读操作来读取带外数据,而应该像读取普通数据那样读取带外数据。YES
SO_LINGERintger若有数据待发送,则延迟关闭。YES
IPPROTO_IPIP_TOSint服务类型
(IPv4选项)IP_TTLint存活时间
IPPROTO_IPV6IPV6_NEXTHOPsockaddr_in6下一跳IP地址
(IPv6选项)IPV6_RECVPKTINFOint接受分组信息
IPV6_DONTFRAGint禁止分片
IPV6_RECVTCLASSint接受通信类型
IPPROTO_TCPTCP_MAXSEGintTCP最大报文段大小YES
(TCP选项)TCP_NODELAYint禁止Nagle算法YES

服务器 而言,部分socket选项 只能在调用 listen 系统调用前 针对 socket 设置才有效。这是因为连接 socket 只能由 accept 调用返回,而 acceptlisten 监听队列 中接受的连接至少是个 半连接 ,这说明 服务器 已经往 客户端 上发送出了 TCP同步报文段(执行完了三次握手中的前两次)。但 部分 socket 选项只能在 TCP同步报文中设置 ,如:TCP最大报文段选项。对此有两种解决方案:

  • 对于服务器而言,执行 listen系统调用 时设置这些 socket选项,那么 accept 返回的 连接socket 将自动继承这些选项(注1)
  • 对于客户端而言,这些 socket选项 应该在调用 connect函数 之前设置,因为 connect 调用成功之后三次握手已完成。

注1

这些选项包括:SO_DEBUG、SO_DONTROUTE、SO_KEEPALIVE、SO_LINGER、SO_OBBINLINE、SO_RCVBUF、SO_RCVLOWAT、TCP_MAXSEG、TCP_NODELAY 。


SO_REUSEADDR

服务器程序可以通过设置本选项来强制使用被处于 TIME_WAIT 状态的连接占用的 socket 地址。此外,我们也可以通过修改内核参数 /proc/sys/net/ipv4/tcp_tw_recycle 来快速回收被关闭的 socket,甚至使 TCP 连接根本就不进入 TIME_WAIT 状态。

int sock = socket( PF_INET, SOCK_STREAM, 0); // TCP协议,IPv4版本,基于流服务,0:使用默认协议
assert( sock >= 0); // 检测创建sock是否成功
int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse) );
// 操作描述符为sock的socket套接字,操作的属性是通用socket选项
// 选项类型为SO_REUSEADDR,SO_REUSEADDR的数据类型为int
// 1即为启用SO_REUSEADDR选项

SO_RCVBUF 和 SO_SNDBUF

这两个选项分别用来表示 TCP 接收缓冲区大小和发送缓冲区大小。不过,当我们 通过setsockopt 来设置 TCP 的接收、发送缓冲区大小时,系统都会将其值加倍,并且不小于某个值。

一般来讲,TCP 接收缓冲区的最小值是 256 字节,发送缓冲区的最小值是 2048 字节(不同操作系统可能有差异)。我们可以直接修改内核参数 /proc/sys/net/ipv4/tcp_rmem/proc/sys/net/ipv4/tcp_wmem 来强制缓冲区没有最小值限制。

/* 先设置 TCP 接收缓冲区的大小,然后立即读取 */
setsockopt( sock, SOL_SOCKET, SO_RCVBUF, &recvbuf, sizeof(recvbuf) );
getsockopt( sock, SOL_SOCKET, SO_RCVBUF, &recvbuf, ( socklen_t* )&len );
// sock 为目标套接字的文件描述符
// recvbuf 为设定的缓冲区大小
// len=sizeof( recvbuf );

SO_RCVLOWAT 和 SO_SNDLOWAT

该两个选项分别表示接收、发送缓冲区的低水位标记。一般被 I/O复用系统调用 用来判断 socket 是否可读或可写:

  • 接收缓冲区中 可读数据的总数大于其低水位标记时,I/O复用系统调用 将通知应用程序可以从对应的 socket 上读取数据
  • 发送缓冲区 中的空闲空间大于其低水位标记时,I/O复用系统调用 将通知应用程序可以往对应的 socket 上写入数据。

默认情况下,两者均为 1字节


SO_LINGER 选项

该选项用于控制 close系统调用 在关闭 TCP 连接时的行为。默认情况下,当我们使用 close系统调用 来关闭一个 socket 时,close 将立即返回,TCP 模块负责把该 socket 对应的 TCP 发送缓冲区中残留的数据发送给对方。

设置(获取)SO_LINGER 选项的值时,我们需要给 setsockopt(getsockopt)系统调用传递一个 linger 类型的结构体:

#include <sys/socket.h>struct linger{int l_onoff; // 开启(非0)/关闭(0)该选项int l_linger; // 滞留时间
};

根据 linger 结构体中两个成员变量的不同值,close 系统调用可能产生如下行为:

  • l_onoff 等于 0。 此时 SO_LINGER 选项不起作用,close 用默认行为来关闭 socket
  • l_onoff 不为 0,l_linger 等于 0。 此时 close系统调用 立即返回,TCP模块 将丢弃被关闭的 socket 对应的 TCP发送缓冲区 中残留的数据,同时给对方发送一个 复位报文段。这为服务器提供了异常终止一个连接的方法。
  • l_onoff 不为 0,l_linger 大于 0。 此时 close 的行为取决于两个条件:
    1. 被关闭的 socket 对应的 发送缓冲区 中是否还有残留的数据;
    2. socket 是阻塞的还是非阻塞的,阻塞: close 将等待一段长为 l_linger 的时间,直到 TCP模板 发送完所有残留数据并得到对方的确认。如果没发送完并得到确认,则 close 返回 -1 并设置 errnoEWOULDBLOCK非阻塞: close 将立即返回,此时需要根据其 返回值errno 来判断残留数据是否发送完毕。

网络信息API

gethostbyname 和 gethostbyaddr

  • gethostbyname: 根据主机名称获取主机的完整信息。通常先在本地的 /etc/hosts 配置文件中查找主机,没有找到再去访问 DNS 服务器。
  • gethostbyaddr: 根据IP地址获取主机的完整信息。
#include<netdb.h>
struct hostent* gethostbyname( const char* name );
struct hostent* gethostbyaddr( const void* addr, size_t len, int type );
// len IIP地址长度
// type 指定addr所指IP地址的类型,可以是AF_INET或AFINET6

两者的返回类型都是 hostent 结构体类型的指针:

#include<netdb.h>
struct hostent{char* h_name; // 主机名char** h_aliases; // 主机别名列表,可有多个int h_addrtype; // 地址类型(地址族)int h_length; // 地址长度char** h_addr_list; // 按网络字节序列出的主机IP地址列表
};

getservbyname 和 getservbyport

根据名称/端口号获得某个服务的完整信息。实际上都是通过读取 /etc/services 文件来获取服务的信息的。

#include<netdb.h>
struct servent* getservbyname( const char* name, const char* proto );
struct servent* getservbyport( int port, const char* proto );
// name 目标服务的名字
// port 目标服务对应的端口号
// proto 服务类型,tcp表流服务、udp表数据报服务、NULL表获取所有类型的服务

两者的返回类型都是 servent 结构体类型的指针:

#include<netdb.h>
struct servent{char* s_name; // 服务名称char** s_aliases; // 服务别名列表,可有多个int s_port; // 端口号char* s_proto; // 服务类型,通常是 tcp 或 udp
};

不可重入

gethostbynamegethostbyaddrgetservbynamegetservbyport 都是不可重入的,即非线程安全的。但是 netdb.h 头文件给出了它们的可重入版本:在原函数名尾部加上 _r(re-entrant)


getaddrinfo

既能通过主机名获取 IP 地址(内部使用的是 gethostbyname),也能通过服务名获取端口号(内部使用的是 getservbyname),是否可重入取决于内部调用的函数( gethostbynamegetservbyname )是否是它们的可重入版本。

#include<netdb.h>
int getaddrinfo( const char* hostname, const char* service, const struct addrinfo* hints, struct addrinfo** result );
// hostname:可以接收主机名(服务名)/字符串表示的IP地址【IPv4使用点分十进制字符串、IPv6使用十六进制字符串】
// service:可以接收服务名/字符串表示的十进制端口号
// hints:可以为NULL,表示允许反馈任何可用的结果。
// result:指向一个用于存储反馈结果的链表

getaddrinfo 将隐式分配堆内存,因此调用结束后,必须释放这块内存:

#include <netdb.h>
void freeaddrinfo( struct addrinfo* res );

getaddrinfo 反馈的每一条结果都是 addinfo 结构体类型的对象:

struct addrinfo
{int ai_flags; // 标志int ai_family; // 地址族int ai_socktype; // 服务类型,SOCK_STREAM或SOCK_DGRAMint ai_protocol; // 具体的网络协议,等同于socket系统调用的第三个参数,常被设为0以表自动匹配对应协议。socklen_t ai_addrlen; // socket地址ai_addr的长度char* ai_canonname; // 主机的别名struct sockaddr* ai_addr; // 指向socket地址struct addrinfo* ai_next; // 指向下一个 sockinfo 结构的对象
};

ai_flags成员可以取下表中的标志的按位或:

选项含义
AI_PASSIVE套接字地址将用于调用 bind 函数,服务器通常需要设置以表接受任何本地 socket 地址上的服务请求。客户端不能设置。
AI_CANONNAME返回主机的别名
AI_NUMERICHOSThostname 参数必须是IP地址字符串,避免了DNS查询。
AI_NUMERICSERV强制 service 参数必须是十进制端口号字符串,不能是服务名。
AI_V4MAPPED如果对 IPv6 地址的 getaddrinfo 请求失败,则将 IPv4 映射为 IPv6 地址格式。
AI_ALL必须和 AI_V4MAPPED 同时使用,否则将被忽略。同时返回 符合条件由IPv4转换而来IPv6地址
AI_ADDRCONFIG只有至少配置了一个IPv4/IPv6地址(除了回路地址)后,getaddrinfo 才会解析。和 AI_V4MAPPED 互斥。

当我们使用 hints 参数时,可以设置 addrinfo 中前四个成员,其他成员必须设置为 NULL


getnameinfo

内部使用 gethostbyaddrgetservbyport,是否可重入取决于内部调用的函数版本是否可重入:

#include<netdb.h>
int getnameinfo( const struct sockaddr* sockaddr, socklen_t addrlen, char* host, socklen_t hostlen, char* serv, socklen_t servlen, int flags );
// 将返回的主机名(服务名)存储在 host(serv) 参数指向的缓存中
// flags控制getnameinfo的行为

getaddrinfogetnameinfo 成功时返回0,失败返回错误码。Linux下 strerror 函数能将数值错误码 error 转换为易读的字符串形式:

#include<netdb.h>
const char* gai_strerror( int error );

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443731.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux | 高级I/O函数

文章目录创建文件描述符的函数pipe函数dup函数、dup2函数读取或写入数据readv函数、writev函数零拷贝sendfile函数splice函数tee函数进程间通信——共享内存mmap函数 和 munmap函数控制文件描述符fcntl函数创建文件描述符的函数 pipe函数 不再赘述&#xff0c;详情见我的另一…

分布式理论:CAP、BASE | 分布式存储与一致性哈希

文章目录分布式理论CAP定理BASE理论分布式存储与一致性哈希简单哈希一致性哈希虚拟节点分布式理论 CAP定理 一致性&#xff08;Consistency&#xff09;&#xff1a; 在分布式系统中的所有数据副本&#xff0c;在同一时刻是否一致&#xff08;所有节点访问同一份最新的数据副…

Tomcat服务器性能优化

一、概述 本文档主要介绍了Tomcat的性能调优的原理和方法。可作为公司技术人员为客户Tomcat系统调优的技术指南&#xff0c;也可以提供给客户的技术人员作为他们性能调优的指导手册。 二、调优分类 由于Tomcat的运行依赖于JVM&#xff0c;从虚拟机的角度我们把Tomcat的调整分为…

分布式系统概念 | 分布式事务:2PC、3PC、本地消息表

文章目录分布式事务2PC&#xff08;二阶段提交协议&#xff09;执行流程优缺点3PC&#xff08;三阶段提交协议&#xff09;执行流程优缺点本地消息表&#xff08;异步确保&#xff09;分布式事务 分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分…

数据结构算法 | 单调栈

文章目录算法概述题目下一个更大的元素 I思路代码下一个更大元素 II思路代码132 模式思路代码接雨水思路算法概述 当题目出现 「找到最近一个比其大的元素」 的字眼时&#xff0c;自然会想到 「单调栈」 。——三叶姐 单调栈以严格递增or递减的规则将无序的数列进行选择性排序…

最长下降子序列

文章目录题目解法DP暴搜思路代码实现贪心二分思路代码实现题目 给出一组数据 nums&#xff0c;求出其最长下降子序列&#xff08;子序列允许不连续&#xff09;的长度。&#xff08;类似于lc的最长递增子序列&#xff09; 示例&#xff1a; 输入&#xff1a; 6 // 数组元素个…

Linux 服务器程序规范、服务器日志、用户、进程间的关系

文章目录服务器程序规范日志rsyslogd 守护进程syslog函数openlog函数setlogmask函数closelog函数用户进程间的关系进程组会话系统资源限制改变工作目录和根目录服务器程序后台化服务器程序规范 Linux 服务器程序一般以后台进程&#xff08;守护进程[daemon]&#xff09;形式运…

IO模型 :阻塞IO、非阻塞IO、信号驱动IO、异步IO、多路复用IO

文章目录IO模型阻塞IO非阻塞IO信号驱动IO多路复用IO异步IOIO模型 根据各自的特性不同&#xff0c;IO模型被分为阻塞IO、非阻塞IO、信号驱动IO、异步IO、多路复用IO五类。 最主要的两个区别就是阻塞与非阻塞&#xff0c;同步与异步。 阻塞与非阻塞 阻塞与非阻塞最主要的区别就…

Tomcat服务器集群与负载均衡实现

一、前言 在单一的服务器上执行WEB应用程序有一些重大的问题&#xff0c;当网站成功建成并开始接受大量请求时&#xff0c;单一服务器终究无法满足需要处理的负荷量&#xff0c;所以就有点显得有点力不从心了。另外一个常见的问题是会产生单点故障&#xff0c;如果该服务器坏掉…

Linux服务器 | 事件处理模式:Reactor模式、Proactor模式

文章目录Reactor模式Proactor模式同步I/O模型模拟Proactor模式两者的优缺点ReactorProactor同步I/O模型通常用于实现 Reactor 模式&#xff0c;异步I/O模型通常用于实现 Proactor 模式。&#xff08;不是绝对的&#xff0c;同步I/O也可模拟出 Proactor 模式&#xff09; React…

Linux服务器 | 服务器模型与三个模块、两种并发模式:半同步/半异步、领导者/追随者

文章目录两种服务器模型及三个模块C/S模型P2P模型I/O处理单元、逻辑单元、存储单元并发同步与异步半同步/半异步模式变体&#xff1a;半同步/半反应堆模式改进&#xff1a;高效的半同步/半异步模式领导者/追随者模式组件 &#xff1a;句柄集、线程集、事件处理器工作流程两种服…

香农信息熵之可怜的小猪

文章目录题目解析香农熵公式样例具体分析代码题目 有 n 桶液体&#xff0c;其其中 正好 有一桶含有毒药&#xff0c;其装的都是水。它们从外观看起来都一样。为了弄清楚哪只水桶含有毒药&#xff0c;你可以喂一些猪喝&#xff0c;通过观察猪是否会死进行判断&#xff0c;实验对…

字符串匹配之KMP(KnuthMorrisPratt)算法(图解)

文章目录最长相等前后缀next数组概念代码实现图解GetNext中的回溯改进代码实现代码复杂度分析最长相等前后缀 给出一个字符串 ababa 前缀集合&#xff1a;{a, ab, aba, abab} 后缀集合&#xff1a;{a, ba, aba, baba} 相等前后缀 即上面用同样颜色标识出来的集合元素&#…

linux下tomcat6.0与jdk安装详细步骤

安装Tomcat6.0和JDK1.6 在linux系统上安装tomcat和jdk应该说是我学习linux知识的第一课了&#xff0c;之前只 是听说过&#xff0c;从没接触过&#xff0c;但我们公司项目都是部署在linux系统上的&#xff0c;那天上司突 然给我发了几个文档&#xff0c;让我看一下&#xff…

Android入门(一) | Android Studio的配置与使用

文章目录安装配置Android Studio使用Android Studio模拟器更改Android SDK的路径Hello World&#xff01;安装配置Android Studio 从这一步开始&#xff1a; 一直点 next 即可&#xff0c;直到存储路径的选择上&#xff0c;可以放到非 C 盘&#xff0c;这里我放到 D 盘了&am…

Android 入门(四) | Intent 实现 Activity 切换

文章目录Intent显式 Intent定义两个 xml 文件android:orientationmatch_parent 和 wrap_contentIntent函数定义两个 Activity隐式 Intent更多隐式 Intent 的用法用隐式 Intent 打开系统浏览器自建 Activity 以响应打开网页的 Intent向下一个活动传递数据返回数据给上一个活动In…

Android入门(二) | 项目目录及主要文件作用分析

文章目录项目目录分析app目录分析AndroidManifest.xml 分析MainActivity.kt 分析build.gradle 分析最外层目录下的 build.gradleapp 目录下的 build.gradle项目目录分析 我们来看一下 src/main/res 下的一些文件&#xff1a; .gradle 和 .idea &#xff1a;这两个目录下放置…

Android入门(三) | Android 的日志工具 Logcat

文章目录日志工具类 android.util.LogLogcat 中的过滤器日志工具类 android.util.Log Log 从属日志工具类 android.util.Log &#xff0c;该类提供了五个方法供我们打印日志&#xff1a; Log.v() &#xff1a;用于打印那些最为琐碎的、意义最小的日志信息。对应级别 verbose&…

Android 客户端与服务器交互方式

突然想到一个问题就是Android客户端与服务器交互有几种方式&#xff0c;因为在脑袋里想当然的就是webservices和json。要在Android手机客户端与pc服务器交互&#xff0c;需要满足下面几种条件&#xff1a;跨平台、传输数据格式标准、交互方便...。 为了与服务器通讯其实无非就…

Android入门(五) | Activity 的生命周期

文章目录Activity 的状态及生命周期实现管理生命周期FirstActivitySecondActivityDialogActivity运行结果旧活动被回收了还能返回吗&#xff1f;Activity 的状态及生命周期 Android 的应用程序运用 栈&#xff08;Back Stack&#xff09; 的思想来管理 Activity&#xff1a; …