浅谈Linux环境下Socket选项的设置
0.前言
TCP/IP协议栈是Linux内核的重要组成部分和网络编程的基石,虽然Linux和BSD有很大的联系,但是对于某些Socket选项和内核操作仍然存在差异,因此文中适用场景均为CentOS环境。
《UNIX网络编程》是已故UNIX网络专家W. Richard Stevens博士(1951-1999)、世界著名网络专家Bill Fenner和Andrew M. Rudoff完成的权威著作,该书对网络编程进行全面而深入的阐述,是提高网络编程功力的不二之选。
通过本文将了解到以下内容:
1.socket层和TCP/IP协议的区别和联系
2.操作socket的基础API和简单实用方法
3.常用Socket选项举例
1.Socket和TCP/IP的关系
"All problems in computer science can be solved by another level of indirection."
为满足应用层需求,系统对TCP/IP层进行细节屏蔽和抽象,Socket层就相当于TCP/IP和应用层之间的中间层。
常用的socket/bind/accept/connect就是抽象出来的接口,使用它们可以快速进行网络程序开发,可见Socket中间层的重要性,Socket选项就是为满足用户的定制化需求而生的。我们经常遇到的情况包括地址复用、端口复用、读写超时时间、读写缓冲区大小等。
在Linux的TCP/IP协议栈中包括很多Socket选项,它们会出现在TCP层、IP层、Socket层等,为此在读取和设置socket选项时需要指定level。
如图可以看到Socket层作为中间层以及各层支持的部分Socket选项:
注:可通过man 7 tcp/man 7 ip查看tcp/ip各层Socket选项详细定义和添加内核版本等信息。
2.操作Socket选项的API
读取和设置Socket选项的API包括:getsockopt、setsockopt、fcntl、ioctl等;
其中fcntl和ioctl用来设置socket的阻塞和非阻塞状态。
通过man获得的函数定义:
/ioctl函数定义 #include <sys/ioctl.h> int ioctl(int d, int request, ...); //fcntl函数定义 #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); //get/setsockopt函数定义 #include <sys/types.h> #include <sys/socket.h> int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen); int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
3.get/setsockopt使用说明
使用时需要按照函数要求的形参格式进行传递,显式指明其所在的level以及选项名称optname、optval类型和长度optlen。
- level参数说明
从sys/socket.h的源码中可以看到对于level的说明如下:
/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ #define SOL_IP 0 #define SOL_IPX 256 #define SOL_AX25 257 #define SOL_ATALK 258 #define SOL_NETROM 259 #define SOL_TCP 6 #define SOL_UDP 17 #define SOL_SOCKET 0xffff
- optval和optlen参数说明
optval和optlen均为指针类型,这两个参数与当前操作的option有直接关系,可以看到optval使用void*类型,optlen使用socklen_t*类型。
socklen_t类型说明:socklen_t和int应该具有相同的长度,否则会破坏 BSD套接字层的填充,POSIX开始时候用的是size_t。
吃瓜时间:Linus Torvalds 向他们解释使用size_t是完全错误的,因为在64位结构中 size_t和int的长度是不一样的,而这个参数的长度必须和int一致,最终POSIX的那帮家伙找到了解决的办法,创造了 一个新的类型socklen_t。
Linux Torvalds说这是由于他们发现了自己的错误但又不好意思承认,所以另外创造了一个新的数据类型。
指针使用:optval和optlen两个指针类型是缺一不可的,optval为void*类型如果没有长度说明,系统函数在调用时就无法获取边界,optlen为底层调用指明内存起始地址对应的偏移量,这是C中常用的指针操作模式。
Socket选项多是int和bool类型 但是也有一些复合类型比如linger,因此在读写选项是对于optval和optlen的编写要根据实际而定。
4. SO_REUSEADDR选项
典型场景:
在《Unix网络编程》卷一中指出了SO_REUSEADDR的重要使用场景:当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
TIME_WAIT:如何优雅关闭Socket是个值得思考的问题, TIME_WAIT状态是TCP协议为了保证全双工连接可靠性设置的,感兴趣可以查阅TIME_WAIT的作用,并不要一味的谈TIME_WAIT色变,这里就不展开了。
设置方法:
未设置SO_REUSEADDR,在重启时就会绑定失败显示资源被占用,需要等待该IP+Port被释放才可以重启成功,该问题对于线上服务不可接受。因此需要将服务端的socket设置为地址复用:
; setsocketopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void*)&enable,sizeof(enable));
5. SO_REUSEPORT选项
作用效果:
端口复用选项SO_REUSEPORT是在SO_REUSEADDR之后于Linux3.9版本加入的,并不是所有系统都支持该选项。SO_REUSEPORT允许多个进程监听相同的IP和Port,但是为了防止端口劫持增加了对进程所属用户的限制。
内核支持:
端口复用选项是个非常大的进步,有利于服务端程序扩展、提高并发能力。值得一提的是SO_REUSEPORT在内核层面实现了简单的负载均衡,为监听的多个进程进行流量分发。Nginx应用:Nginx的1.9.1版本引入了SO_REUSEPORT套接字选项,对于Nginx而言,启用该选项可以减少在某些场景下的锁竞争而改善性能。Linux 3.9版本和Nginx1.9.1版本(含)之后的版本,Nginx已经无需再使用互斥锁ngx_use_accept_mutex,引入SO_REUSEPORT选项由内核层面实现负责均衡来解决惊群问题。
6. TCP_NODELAY选项
简单背景:
为解决福特公司局域网拥塞问题,Nagle算法由福特公司的John Nagle 在1984年提出。同时代的其他网络也存在这种情况,因此Naggle算法被引入到协议栈。
算法原则:
尽可能发送大块数据,避免网络中充斥着许多小数据块,任意时刻最多只能有一个未被确认的小段。未被确认是指一个数据块发送出去后,没有收到对方发送的ACK确认。
通俗解释:
就是在两座城市的高速路上之前充斥着非常多的货车,货车的车厢中可能是一根羽毛、一个玩具熊或者一台机器等,造成了高速路的拥堵。为此要求每次最多只有一辆未被授权的货车行驶且每个货车装载尽可能多的东西,从而提高单次运输效率和降低货车数量,缓解高速路的拥堵。
算法弊端:
上世纪80年代网络带宽有限,Nagle算法有效改善了网络拥塞情况,但是随着网络带宽的增加和通信基础设施水平的提高,最多只能有一个未被确认的小段的限制导致了无意义的等待,无法有效利用当前的网络带宽。
算法禁用:
TCP_NODELAY可以解决Nagle算法带来的问题,开启TCP_NODELAY意味着允许小包的发送且不强制等待,对时效高且数据量小的应用非常实用。从应用程序的角度来说应该尽量避免写小包,从而实现数据包大小和数据包数量的效率最大化。
7. 小结
在了解了Socket作为TCP/IP层和应用层在网络编程领域的中间层之后,进一步明确读写套接字选项的函数,以及常见的套接字选项的设置方法以及设置原因,从而对整个套接字选项有一个基本认识。
套接字选项本身很多,但是我们常用的并不多,需要根据自己的实际情况和该选项的作用来进行调整,不理解背后机理的调整多半会留坑。
浅谈Linux环境下Socket选项的设置的更多相关文章
- 浅谈Windows环境下DOS及MS-DOS以及常见一些命令的介绍
浅谈Windows环境下DOS及MS-DOS以及常见一些命令的介绍 前记 自己是搞编程的,首先我是一个菜鸟,接触计算机这么久了,感觉很多计算机方面的技术和知识朦朦胧胧.模模糊糊,貌似有些贻笑大方了:所 ...
- Linux环境下Oracle安装参数设置
前面讲了虚拟机的设置和OracleLinux的安装,接下来我们来说下Oracle安装前的准备工作.1.系统信息查看系统信息查看首先服务器ip:192.168.8.120服务器系统:Oracle Lin ...
- 由一个简单需求到Linux环境下的syslog、unix domain socket
本文记录了因为一个简单的日志需求,继而对linux环境下syslog.rsyslog.unix domain socket的学习.本文关注使用层面,并不涉及rsyslog的实现原理,感兴趣的读者可以参 ...
- []转帖] 浅谈Linux下的五种I/O模型
浅谈Linux下的五种I/O模型 https://www.cnblogs.com/chy2055/p/5220793.html 一.关于I/O模型的引出 我们都知道,为了OS的安全性等的考虑,进程是 ...
- 浅谈Linux下/etc/passwd文件
浅谈Linux 下/etc/passwd文件 看过了很多渗透测试的文章,发现在很多文章中都会有/etc/passwd这个文件,那么,这个文件中到底有些什么内容呢?下面我们来详细的介绍一下. 在Linu ...
- 浅谈Linux下傻瓜式磁盘分区工具cfdisk的使用
对于新手来说,Linux环境下的磁盘分区可能还会存在一些困难.对于熟悉Linux的朋友来说,我们还有fdisk.parted(2TB以上的磁盘分区使用)等磁盘分区工具可以使用.在我们新增磁盘或者在原来 ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- mosquitto在Linux环境下的部署/安装/使用/测试
mosquitto在Linux环境下的部署 看了有三四天的的源码,(当然没怎么好好看了),突然发现对mosquitto的源码有了一点点感觉,于是在第五天决定在Linux环境下部署mosquitto. ...
- C语言 linux环境基于socket的简易即时通信程序
转载请注明出处:http://www.cnblogs.com/kevince/p/3891033.html ——By Kevince 最近在看linux网络编程相关,现学现卖,就写了一个简易 ...
随机推荐
- Lerp
Lerp,就是返回两个值之间的插值,一般有三个参数.第一个参数为初始值,第二个参数为最终值,插值为0~1d的一个浮点数值,为0时为初始值,1时为最终值,为0到1之间的数值时返回一个混合数值.若第三个参 ...
- vi / vim 基本操作
进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi n filename :打开文件,并将光标置于第n行首 vi filename :打开 ...
- MySQL Lock--gap before rec insert intention waiting
在事务插入数据过程中,为防止其他事务向索引上该位置插入数据,会在插入之前先申请插入意向范围锁,而如果申请插入意向范围锁被阻塞,则事务处于gap before rec insert intention ...
- CentOS上使用ntfs-3g挂载NTFS分区
U盘做过系统盘,是NTFS格式的,Centos7竟然不识别,而且因为一些原因,我的服务器没有联网,只能用U盘 查过资料才知道Centos7上默认是不支持挂载NTFS格式的分区的,需要安装ntfs-3g ...
- error: invalid-first-character-of-tag-name错误解决方案
HTML 特殊字符写法要用原始码,例如: ‘<’ 原始码为 < ‘>’ 原始码为 > 解决示例: 原错误代码 <div><</div> 修改后代码 ...
- 个性化排序算法实践(三)——deepFM算法
FM通过对于每一位特征的隐变量内积来提取特征组合,最后的结果也不错,虽然理论上FM可以对高阶特征组合进行建模,但实际上因为计算复杂度原因,一般都只用到了二阶特征组合.对于高阶特征组合来说,我们很自然想 ...
- linux网络编程之socket编程(三)
今天继续对socket编程进行学习,在学习之前,需要回顾一下上一篇中编写的回射客户/服务器程序(http://www.cnblogs.com/webor2006/p/3923254.html),因为今 ...
- mysql开发相关
1.mysql事务原理,特性,事务并发控制2.如何解决高并发场景下的插入重复3.乐观锁和悲观锁4.常用数据库引擎之间区别5.mysql索引6.B-Tree7.mysql索引类型8.什么时候创建索引9. ...
- P2018 消息传递[dp]
题目描述 巴蜀国的社会等级森严,除了国王之外,每个人均有且只有一个直接上级,当然国王没有上级.如果A是B的上级,B是C的上级,那么A就是C的上级.绝对不会出现这样的关系:A是B的上级,B也是A的上级. ...
- SVM:从数学上分析为什么优化cost function会产生大距离(margin)分类器
向量内积 uTv = vTu为两个二维向量的内积,它等于p*||u||(其中p为向量v在向量u上的投影长度,是有+/-之分的,||u||为向量u的长度也称为范数),它是一个实数(是一个标量). 如上图 ...