Linux/Unix系统编程手册--SOCKET章节读书笔记
2015-07-21 19:19
691 查看
SOCKET章节读书笔记
强烈推荐Linux/Unix系统编程手册,号称超越APUE的神书。backlog含义
#include <sys/socket.h> int listen(int socketfd, int backlog)
backlog参数限制未决连接(未accept)的数量,在这个数量之内,connect会立刻成功。
Linux上上限为128,定义在
udp已连接socket
udp socket也是可以调用connect()的,这种叫已连接socket,内核会记录这个socket的对等socket的地址。当一个udp socket已连接之后:
1.数据包发送可使用write或send,会自动发送到对等socket上,与sendto一样,每个write会发送一个独立的数据包
2.在这个socket上只能读取对等socket发送的数据**
零时端口
未调用bind(),tcp/udp会分配一个零时端口(tcp服务器也可以不调用bind)可通过/proc/sys/net/ipv4/ip_local_port_range来修改范围,一般做高并发测试时,测试机可能需要修改以支持多并发。
UDP避免IP分段
一般来说,UDP会采用保守的方法来避免IP分段,即确保传输的IP数据包的大小小于IPv4组缓冲区576字节。8自己udp头部,至少需要20字节存放IP头,剩下548字节存放UDP数据包。实践中,一般会选择512来存放数据包。shutdown与close区别
SHUT_WR被称为半关闭套接字,通过文件结尾来通知对端本地的写端已经关闭了。shoutdown与close一个重要区别:无论该套接字上是否还关联其它的文件描述符,shotdown都会关闭套接字通道。
如sockfd指向一个已连接的流式套接字,执行以下调用,连接依然保持打开,仍然可以通过文件描述符fd2在该连接上做i/o操作。
fd2=dup(sockfd); close(sockfd);
但如果执行以下调用,那么连接的双向通道都会关闭,通过fd2无法执行i/o操作.
fd2=dup(sockfd); shutdown(sockfd,SHUT_RDWR);
如果套接字文件描述符fork()被复制,如果fork()后,一个进程在描述符副本上执行SHUT_RDWR操作,那么其它进程都无法在这个文件描述符上执行i/o操作了。
需要注意的是,shutdown并不会关闭文件描述符,要关闭文件描述符,还需调用clsoe。
TCP_CORK套接字选项
HTTP中使用sendfile()发送文件,为提供带宽利用率,可使用TCP_CORK将HTTP首部给缓冲,与数据报文合并为一个报文。int optval =1 setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval); write(sockfd, ...); //write http headers sendfile(sockfd,...); // send data optval =0 setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval));
TIME_WAIT状态
TIME_WAIT状态值出现在执行主动关闭的一端,迁移到CLOSED状态需要2MSL(报文最大生存时间)。MSL是IP报文在吃过TTL限制前可在网络中生存的最大估计时间。Linux中TIME_WAIT将持续60s。
目的:
1.实现可靠的连接终止
如果最后发送的ACK丢失了,等待2MSL可以重新发送最后ACK;而如果主动关闭的一方不存在了,TCP协议将发送RST报文(RST会被解释为错误)
2.让老的重复的报文段在网络中过期失效,这样建立新的连接时将不再接受它们
当有TCP节点处于TIME_WAIT状态时是无法通过同样的IP和端口号重新建立新的连接的。SO_REUSEADDR选项可用来避免会遇到EADDRINUSE错误,同时仍然允许TIME_WAIT状态提供可靠性保证。
带外数据
send()和recv()需要制定MSG_OOB标志,当套接字接受到带外数据通知时,内核为套接字属主(通常为使用该套接字的进程)生成SIGURG信号。带外数据是TCP套接字的一种特性,允许发送端将传送的数据标记为高优先级。TCP通过URG标志位来标示有紧急(带外)数据,并将紧急指针指向紧急数据,但TCP没有执行紧急数据长度,因此认为紧急数据只由一个字节组成。telnet,ftp等,都利用该特性来终止之前传送的命令。
s.send("hello",socket.MSG_OOB) c.recv(100,socket.MSG_OOB) // "o" c.recv(100) // "hell"
分散聚合IO
readv和writev可以一次系统调用读写多个非连续缓冲区#include <sys/uio.h> ssize_t readv(int filedes, const struct iovec *iov, int iovcnt); ssize_t writev(int filedes, const struct iovec *iov, int iovcnt) struct iovec{ void *iov_base; //buffer size_t iov_len; //size of buffer }
I/O多路复用,信号驱动,epoll
水平触发通知:如果文件描述法上可以非阻塞的执行I/O系统调用,此时认为它已经就绪。所以每次不需要读取很多数据,多个描述符读取平衡。
边缘触发通知:
如果文件描述符自上次状态检查以来有了新的I/O活动,此时触发通知。由于只有新状态才通知,所以一次需要读取所有数据,不然会导致数据丢失,会导致其他描述符处于饥饿状态。
I/O模式 | 水平触发 | 边缘触发 |
---|---|---|
select,poll | yes | |
信号驱动I/O | yes | |
epoll | yes | yes |
select
#include <sys/time.h> #incldue <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timevel *timeout) 返回就绪(3个集合)的描述符数量,0 超时,-1 错误
exceptfds一般只会在下面两种情况发生:
1.连接到信包模式下的伪终端主设备上的从设备状态发生改变
2.tcp套接字接收到了带外数据
nfds是集合中最大文件描述符+1,目的是让select变得更有效率,内核不用检查大于这个值的描述符是否属于这个集合。
eopll
max_user_watches:每个用户可以注册到epoll实例上的文件描述符总数(/proc/sys/fs/epoll/max_user_watches,默认的上学值是根据系统可用内存计算)可以研究研究https://github.com/cloudwu/socket-server,以及tornado源码,这两个都是水平触发的,边缘触发的可以研究nginx或golang,当然nginx更适合。
典型异步I/O读写:
int sz = write(fd, buffer, sz); if (sz < 0) { switch(errno) { case EINTR: continue; case EAGAIN: return -1; } int n = read(fd, buffer, sz); if (n<0) { switch(errno) { case EINTR: break; case EAGAIN: fprintf(stderr, "socket-server: EAGAIN capture.\n"); break; default: // close when error return SOCKET_ERROR; } return -1; }
配置参数
系统限制 /etc/sysctl.conf来自gopush群的分享
net.ipv4.ip_forward = 0 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.default.accept_source_route = 0 kernel.sysrq = 0 kernel.core_uses_pid = 1 kernel.msgmnb = 1048576 kernel.msgmax = 1048576 kernel.shmmax = 68719476736 kernek.shmall = 4294967296 fs.file-max = 1048576 kernel.pid_max = 1048576 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_timestsmps = 0 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_keepalive_time = 1200 net.ipv4.ip_local_port_range = 1024 65535 net.ipv4.tcp_max_syn_backlog = 8192 net.ipv4.tcp_max_tw_buckets = 5000 net.ipv4.tcp_wmem = 4096 4096 1677216 net.ipv4.tcp_rmen = 4096 4096 1677216 net.ipv4.tcp_mem = 94500000 91500000 92700000 net.ipv4.tcp_max_orphans = 3276800 net.core.netdev_max_backlog = 32768 net.core.somaxconn = 32768 net.core.wmem_default = 8388608 net.core.rmem_default = 8388608 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 vm.overcommit_memory = 1
登陆用户限制 /etc/security/limits.conf
soft是警告设置,hard是阀值(鸟哥私房菜)
* soft nofile 150000 * hard nofile 150000
如果不管可直接用ulimit -n 10000设置
相关文章推荐
- Linux设备驱动开发基础
- Linux自学笔记:03_用户管理和目录结构
- Linux下按照时间和大小生成新文件的程序流程及其C代码实现
- Linux最大文件打开数使用经验详解
- Selinux SeAndroid
- Linux学习随笔--再次接触
- 如何在Linux系统Ubuntu版本下安装Python开发包NumPy、Matplotlib、SciPy
- linux: 几个常用makefile模板
- 如何使用Linux块设备分区创建ASM(使用UDEV,而非ASMLIB)
- 怎样往linux社区提交代码
- 查看Linux服务器性能指标
- Linux ./configure
- Linux-git简明教程(一)
- socket结束后如何立刻释放端口
- 使用Cygwin在Windows上体验Linux的快感
- linux下搭建svn版本控制软件
- 将 Linux on x86 应用程序移植到 Linux on Power 的指南
- centOS 安装jdk
- cp命令
- 怎么连接linux系统