redis anet网络通信的源码分析
来源:互联网 发布:火炮分类 知乎 编辑:程序博客网 时间:2024/04/28 09:53
anet是redis对网络通信(socket)的简单封装和一些状态设置的封装。状态设置主要包括ocket连接的阻塞性、
tcp的保活定时器的设置、设置发送缓冲区、tcp的Nagle算法设置、设置发送超时时间、地址重用的设置和设置
socket只能发送和接收ipv6。
一、socket的状态设置
socket的状态选项设置主要通过setsockopt设置。
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);level主要包括SOL_SOCKET:通用套接字选项.、IPPROTO_IP:IP选项、IPPROTO_TCP:TCP选项三个层次,
optname就是具体的状态选项,而redis只用到了这三个层次部分的选项。
1、socket连接的阻塞性
int anetSetBlock(char *err, int fd, int non_block) { int flags; if ((flags = fcntl(fd, F_GETFL)) == -1) { anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno)); return ANET_ERR; } if (non_block) flags |= O_NONBLOCK;//设置socket连接非阻塞 else flags &= ~O_NONBLOCK;//设置socket连接阻塞 if (fcntl(fd, F_SETFL, flags) == -1) { anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno)); return ANET_ERR; } return ANET_OK;}2、tcp的保活定时器的设置
//启用保活定时器int anetTcpKeepAlive(char *err, int fd){ int yes = 1;//yes为1表示启用TCP保活定时器,yes为0表示关闭保活定时器 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) { anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno)); return ANET_ERR; } return ANET_OK;}//启用保活定时器,设置启用保活定时器的具体选项int anetKeepAlive(char *err, int fd, int interval){ int val = 1;//启用保活定时器 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1) { anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno)); return ANET_ERR; } val = interval; //设置对一个连接进行有效性探测之前运行的最大非活跃时间间隔,默认值为 14400(即2个小时) if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) { anetSetError(err, "setsockopt TCP_KEEPIDLE: %s\n", strerror(errno)); return ANET_ERR; } val = interval/3; if (val == 0) val = 1;//设置两个探测的时间间隔,默认值为150即75秒 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { anetSetError(err, "setsockopt TCP_KEEPINTVL: %s\n", strerror(errno)); return ANET_ERR; } val = 3;//设置关闭一个非活跃连接之前进行探测的最大次数 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { anetSetError(err, "setsockopt TCP_KEEPCNT: %s\n", strerror(errno)); return ANET_ERR; } return ANET_OK;}3、tcp的Nagle算法设置
Nagle算法通过将未确认的数据存入缓冲区直到蓄足一个包一起发送的方法,来减少主机发送的零碎小数据
包的数目。这样一来势必会造成通信的延迟,TCP_NODELAY可以用来设置Nagle算法是否启用。
static int anetSetTcpNoDelay(char *err, int fd, int val){//val为1启用Nagle算法,val为0禁止Nagle算法 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1) { anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno)); return ANET_ERR; } return ANET_OK;}4、设置发送缓冲区
int (char *err, int fd, int buffsize){//buffsize为缓冲区大小,SNDBUF表示发送缓冲区,相对SO_RCVBUF表示接收缓冲区 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1) { anetSetError(err, "setsockopt SO_SNDBUF: %s", strerror(errno)); return ANET_ERR; } return ANET_OK;}5、设置发送超时时间
int anetSendTimeout(char *err, int fd, long long ms) { struct timeval tv;//tv为超时时间 tv.tv_sec = ms/1000; tv.tv_usec = (ms%1000)*1000; //SO_SNDTIMEO为发送超时时间,SO_RCVTIMEO为接收超时时间 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) { anetSetError(err, "setsockopt SO_SNDTIMEO: %s", strerror(errno)); return ANET_ERR; } return ANET_OK;}
6、地址重用的设置
SO_REUSEADDR这个选项的设置主要是为了可以使TCP状态位于 TIME_WAIT的地址马上可以投入使用。
static int anetSetReuseAddr(char *err, int fd) { int yes = 1;//yes为1表示允许地址重用,为0表示不允许地址重用 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno)); return ANET_ERR; } return ANET_OK;}7、设置socket只能发送和接收ipv6
static int anetV6Only(char *err, int s) { int yes = 1;//1表示只能发送和接收ipv6 if (setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,&yes,sizeof(yes)) == -1) { anetSetError(err, "setsockopt: %s", strerror(errno)); close(s); return ANET_ERR; } return ANET_OK;}
二、函数汇总
int anetTcpConnect(char *err, char *addr, int port); //进行TCP的阻塞连接 int anetTcpNonBlockConnect(char *err, char *addr, int port); //进行TCP的非阻塞连接 int anetTcpNonBlockBindConnect(char *err, char *addr, int port,char *source_addr);int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port,char *source_addr);int anetUnixConnect(char *err, char *path); //进行Unix域的阻塞连接 int anetUnixNonBlockConnect(char *err, char *path); //进行Unix域的非阻塞连接 static int anetTcpGenericConnect(char *err, char *addr, int port,char *source_addr, int flags);//封装了socket连接操作int anetTcpServer(char *err, int port, char *bindaddr, int backlog);//创建socket的serverint anetTcp6Server(char *err, int port, char *bindaddr, int backlog);//创建只能发送和接收ipv6的socket的serverint anetUnixServer(char *err, char *path, mode_t perm, int backlog);//创建unix域的的socket的serverstatic int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backlog);//封装了socket的监听连接的操作int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port);//获得tcp连接请求并建立连接int anetUnixAccept(char *err, int serversock);//获得unix域连接请求并建立连接static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len);//获得连接请求并建立连接//地址解析函数int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len); /* 解析所有的东西 */int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len); /* 单单解析IP的地址 */int anetGenericResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len,int flags);//根据host解析地址/*-------状态设置函数-------*/int anetNonBlock(char *err, int fd);int anetBlock(char *err, int fd);int anetSetBlock(char *err, int fd, int non_block);//设置socket是否阻塞int anetEnableTcpNoDelay(char *err, int fd); /* 启用TCP连接没有延迟 */int anetDisableTcpNoDelay(char *err, int fd); /* 禁用TCP连接没有延迟 */static int anetSetTcpNoDelay(char *err, int fd, int val);//设置tcp连接是否延迟static int anetV6Only(char *err, int s)//设置socket只能发送和接收ipv6int anetTcpKeepAlive(char *err, int fd); /* 设置TCP启用心跳机制 */int anetPeerToString(int fd, char *ip, size_t ip_len, int *port);//获取对端fd的地址(ip+port)int anetSockName(int fd, char *ip, size_t ip_len, int *port);//获取本端fd的地址(ip+port)int anetKeepAlive(char *err, int fd, int interval); /* 设置tcp心跳机制的TCP_KEEPCNT,TCP_KEEPINTVL,TCP_KEEPIDLE*/int anetSendTimeout(char *err, int fd, long long ms);//发送超时设置static int anetSetReuseAddr(char *err, int fd);//地址重用设置int anetSetSendBuffer(char *err, int fd, int buffsize);//发送缓冲区大小设置//读写操作的简单封装int anetRead(int fd, char *buf, int count); //对read()的简单封装int anetWrite(int fd, char *buf, int count); //对write()的简单封装
0 0
- redis anet网络通信的源码分析
- Redis源码分析(二十一)--- anet网络通信的封装
- redis源码分析(六)- anet网络通讯的封装
- Redis源代码分析之四:Unix底层网络通信——Anet
- 结合redis设计与实现的redis源码学习-15-TCP网络连接(anet.c)
- anet 网络操作函数 redis
- Redis anet
- redis网络部分源码分析
- Redis源码学习之【网络通信框架】
- Redis源码学习之【网络通信框架】
- Zeroc ICE 源码分析三 ICE的网络通信
- 基于TCP网络通信的自动升级程序源码分析--生成升级文件相关的配置文件
- 基于TCP网络通信的自动升级程序源码分析-客户端连接服务器
- 基于TCP网络通信的自动升级程序源码分析-启动升级文件下载程序
- 基于TCP网络通信的自动升级程序源码分析-服务器发送文件
- 基于TCP网络通信的自动升级程序源码分析-客户端接收文件
- C#网络编程-简单的通信源码
- Redis源码分析(二十二)--- networking网络协议传输
- card 驱动(二)读写速度
- 【计算机原理】计算机原理日常回顾总结
- 使用花生壳(内网穿透)服务搭建网站服务
- 微生物生殖
- SQL Server 2014数据库远程访问设置方法
- redis anet网络通信的源码分析
- ssh登录docker容器
- Cocos2d-x 音频功能学习笔记
- 04-java
- SQL 事务提交
- Codeforces 742B
- 运行junit测试报javax/servlet/ServletContext : Unsupported major.minor version 51.0错误
- css引入方式
- 网页分块上传文件