【网络编程】TCPIP-8-套接字的多种选项
前言
说明:
- demo 基于 Linux。
8. 套接字的多种选项
一般创建好套接字后直接使用即可,有些配置是默认的,当然也可以通过以下修改。
8.1 API getsockopt(); & setsockopt();
/*
sock: 用于查看选项套接字文件描述符
level: 要查看的可选项协议层
optname: 要查看的可选项名
optval: 保存查看结果的缓冲地址值
optlen: 向第四个参数传递的缓冲大小。调用函数候,该变量中保存通过第四个参数返回的可选项信息的字节数。
成功时返回 0 ,失败时返回 -1
*/
#include <sys/socket.h>
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
/*
sock: 用于更改选项套接字文件描述符
level: 要更改的可选项协议层
optname: 要更改的可选项名
optval: 保存更改结果的缓冲地址值
optlen: 向第四个参数传递的缓冲大小。调用函数候,该变量中保存通过第四个参数返回的可选项信息的字节数。
成功时返回 0 ,失败时返回 -1
*/
#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
8.2 套接字选项
注意,套接字可选项是分层的。
- SOL_SOCKET:套接字的通用可选项。
- IPPROTO_TCP:可选项是 TCP 协议的相关事项。
- IPPROTO_IP:IP 协议相关事项。
| 协议层 | 选项名 | 读取 | 设置 |
|---|---|---|---|
| SOL_SOCKET | SO_SNDBUF | O | O |
| SOL_SOCKET | SO_RCVBUF | O | O |
| SOL_SOCKET | SO_REUSEADDR | O | O |
| SOL_SOCKET | SO_KEEPALIVE | O | O |
| SOL_SOCKET | SO_BROADCAST | O | O |
| SOL_SOCKET | SO_DONTROUTE | O | O |
| SOL_SOCKET | SO_OOBINLINE | O | O |
| SOL_SOCKET | SO_ERROR | O | X |
| SOL_SOCKET | SO_TYPE | O | X |
| IPPROTO_IP | IP_TOS | O | O |
| IPPROTO_IP | IP_TTL | O | O |
| IPPROTO_IP | IP_MULTICAST_TTL | O | O |
| IPPROTO_IP | IP_MULTICAST_LOOP | O | O |
| IPPROTO_IP | IP_MULTICAST_IF | O | O |
| IPPROTO_TCP | TCP_KEEPALIVE | O | O |
| IPPROTO_TCP | TCP_NODELAY | O | O |
| IPPROTO_TCP | TCP_MAXSEG | O | O |
8.3 缓冲区相关可选项
SO_SNDBUF & SO_RCVBUF
SO_SNDBUF:
- 输出缓冲区相关的可选项。
- 可用其读取当前 I/O 大小,也可以更改缓冲区大小。
SO_RCVBUF:
- 输入缓冲区相关的可选项。
- 可用其读取当前 I/O 大小,也可以更改缓冲区大小。
8.4 端口复用
主要用到 SO_REUSEADDR
先了解一些概念再介绍该选项。
8.4.1 time-wait 状态

MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。
time-wait 状态一般为 2 个MSL。其原因:
- 保证 TCP 协议的全双工连接能够可靠关闭。
- 保证这次连接的重复数据段从网络中消失。保证下次连接收到的数据报文段都是来自新连接的目标端。
- 返回ACK最长为也给MSL,如果没有到达对端,对端重发,到本端最大也要一个MSL,所以得2个MSL。
若服务器先异常断开,四次挥手后进入 time-wait 状态(一般为几分钟),在 time-wait 状态时,该端口还是被占用的。服务器重启后不能正常使用该端口,会输出「bind() error」消息。必须等待该端口被置为 close 状态才能被正常使用。
但是有些情景下是不能接受的,若服务器异常重启,那得等待几分钟才能正常使用。
解决:使用SO_REUSEADDR来解决。
8.4.2 SO_REUSEADDR使用
在套接字的可选项中更改 SO_REUSEADDR 的状态。
适当调整该参数,可将 Time-wait 状态下的套接字端口号重新分配给新的套接字。
SO_REUSEADDR 的默认值为 0。
这就意味着无法分配 Time-wait 状态下的套接字端口号。
因此需要将这个值改成 1 。
参考:
option = TRUE;
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
8.4.3 SO_REUSEADDR 作用
SO_REUSEADDR 作用:
- 当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
- SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可以测试这种情况。
- SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。
- SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。
8.5 Nagle 算法
主要用到 TCP_NODELAY

Nagle 算法:
- 应用于 TCP 层。
- TCP 套接字默认使用 Nagle 算法交换数据。
- 算法:只有接收到前一数据的 ACK 消息, Nagle 算法才发送下一数据。
禁用:
opt_val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&opt_val, sizeof(opt_val));
查看:
getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&opt_val, sizeof(opt_val));
参考
- 《TCP/IP网络编程》
- 李柱明博客-TCP/IP TCP详细笔记
- github 阿婆主
【网络编程】TCPIP-8-套接字的多种选项的更多相关文章
- Unix网络编程--卷一:套接字联网API
UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...
- VC++学习之网络编程中的套接字
VC++学习之网络编程中的套接字 套接字,简单的说就是通信双方的一种约定,用套接字中的相关函数来完成通信过程.应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问 ...
- Linux网络编程:原始套接字简介
Linux网络编程:原始套接字编程 一.原始套接字用途 通常情况下程序员接所接触到的套接字(Socket)为两类: 流式套接字(SOCK_STREAM):一种面向连接的Socket,针对于面向连接的T ...
- 网络编程与socket套接字
网络编程与socket套接字 传输层 PORT协议 port是一种接口,数据通过它在计算机和其他设备(比如打印机,鼠标,键盘或监视器)之间,网络之间和其他直接连接的计算机之间传递 TCP协议 传输 ...
- linux网络编程-(socket套接字编程UDP传输)
今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...
- 【Unix网络编程】chapter3套接字编程简介
chapter3套接字编程简介3.1 概述 地址转换函数在地址的文本表达和他们存放在套接字地址结构中的二进制值之间进行转换.多数现存的IPv4代码使用inet_addr和inet_ntoa这两个函数, ...
- 【Unix网络编程】chapter3 套接字编程简介
chapter3套接字编程简介3.1 概述 地址转换函数在地址的文本表达和他们存放在套接字地址结构中的二进制值之间进行转换.多数现存的IPv4代码使用inet_addr和inet_ntoa这两个函数, ...
- 【网络编程】Socket套接字网络编程模型
一.Linux网络模型 -- Socket套接字编程 图片:Socket 抽象层 Socket编程--不同协议,统一接口 Socket的实质就是一个接口, 利用该接口,用户在使用不同的网络协议时,操作 ...
- python网络编程:socket套接字
一.socket 二.TCP服务器 三.TCP客户端 四.UDP服务器 五.UDP客户端 六.聊天的客户端 七.聊天的服务器 一.socket """ 学习网络编程 其实 ...
- 02网络编程( socket套接字+TCP粘包 )
目录 02 网络编程 一.socket套接字编程 二.简易代码模板 2.1 服务端 2.2 客户端 三.通信循环及代码优化 四.黏包现象 五.struct模块 六.简易版本报头 七.上传文件数据 * ...
随机推荐
- 简单聊一下Uwsgi和Django的爱恨情仇
项目目录:/root/app Uwsgi的配置文件 [uwsgi] # Python扩展包安装的地方 pythonpath=/usr/local/src/python3/lib/python3.5/s ...
- python 12篇 mock接口之flask模块
一.使用pip install flask按照flask模块. import flask,json # 轻量级web开发框架 server = flask.Flask(__name__) @serve ...
- C语言:读TXT 模拟键盘打字输出
//#include<ctype.h> #include<stdio.h> #include <windows.h> //#include "string ...
- 高校表白App-团队冲刺第七天
今天要做什么 使用Fragment进行分屏处理,制作底层 做了什么 完成任务 遇到的问题 因为以前做过了一个,所以这次没有遇到什么问题,开心.啊哈哈
- Leetcode春季打卡第四天:994. 腐烂的橘子
Leetcode春季打卡第四天:994. 腐烂的橘子 Leetcode春季打卡第四天:994. 腐烂的橘子 思路 思路是采用广度优先搜索,一层一层遍历. 首先先扫描矩阵,将坏橘子放进队列,记录正常橘子 ...
- 网络损伤仪WANsim的队列深度功能
什么是队列深度 在网络损伤仪WANsim中,队列是指一个用于缓存报文的缓冲池.深度是指缓冲池可以存储的最大数据量.当WANsim接受的报文超出了带宽限制的量时,溢出的报文会进入队列中. 我们可以在WA ...
- 7.27考试总结(NOIP模拟25)[random·string·queue]
死亡的尽头,没有神 T1 random 解题思路 这波是找规律完胜了.. lby dalao根据样例找出了正确的式子:\(\dfrac{n^2-1}{9}\) 然而,我这个菜鸡却推出了这样一个错误的式 ...
- Mac终端美化(iterm2+zsh+oh-my-zsh+powerlevel10k)
iterm2+zsh+oh-my-zsh+powerlevel10k 一.下载iterm2 方式一:官网下载 https://iterm2.com/ 方式二:百度云下载 链接: https://pan ...
- C++第三十四篇 -- 安装Windows Driver后,编译以前项目出现打不开lib文件
VS2017默认是没有安装WDK的,但是我们写驱动文件的话需要用到WDK.不过安装了WDK后,发现以前一些正常的项目在Release模式下编译会报LINK1104,无法打开.lib的错误 针对这个错误 ...
- Mysql用户、权限、密码管理
一.用户管理 默认:用户root 创建用户: use mysql; create user 'alex'@'192.168.193.200' identified by '123456'; 创建了al ...