Redis在anet.h和anet.c中封装了底层套接字实现:

1.anetTcpServer,建立网络套接字服务器,完成对socket(),bind(),listen()等操作的封装,返回socket的fd。

  1. int anetTcpServer(char *err, int port, char *bindaddr)
  2. {
  3. int s;
  4. struct sockaddr_in sa;                          //见1.1结构体
  5.  
  6. if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR) //AF_INET表示使用IPv4
  7. return ANET_ERR;
  8.  
  9. memset(&sa,0,sizeof(sa));
  10. sa.sin_family = AF_INET;
  11. sa.sin_port = htons(port);
  12. sa.sin_addr.s_addr = htonl(INADDR_ANY);
  13. if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == ) {
  14. anetSetError(err, "invalid bind address");
  15. close(s);
  16. return ANET_ERR;
  17. }
  18. if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
  19. return ANET_ERR;
  20. return s;
  21. }

1.1 结构体sockaddr_in

  1. struct sockaddr_in {
  2. short int sin_family; // Address family
  3. unsigned short int sin_port; // Port number
  4. struct in_addr sin_addr; // Internet address
  5. unsigned char sin_zero[]; // Same size as struct sockaddr
  6. };

1.2 创建socket,封装了socket实现

  1. static int anetCreateSocket(char *err, int domain) {
  2. int s, on = ;
  3. if ((s = socket(domain, SOCK_STREAM, )) == -) { //创建socket
  4. anetSetError(err, "creating socket: %s", strerror(errno));
  5. return ANET_ERR;
  6. }
  7.  
  8. /* Make sure connection-intensive things like the redis benchmark
  9. * will be able to close/open sockets a zillion of times */
  10. if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -) { //设置选项
  11. anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
  12. return ANET_ERR;
  13. }
  14. return s;
  15. }

1.3 memset函数

在C中 <string.h>,原型为:void *memset(void *s, int ch, size_t n);

作用:将s中前n个字节 (typedef unsigned int size_t)用 ch 替换并返回 s 。
memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体数组进行清零操作的一种最快方法。
1.4 网络转头文件:
#include <netinet/in.h>
  1. 定义函数:unsigned short int htons(unsigned short int hostshort);
  2. 函数说明:htons()用来将参数指定的16 hostshort 转换成网络字符顺序.
  3. 返回值:返回对应的网络字符顺序.
  4. 定义函数:unsigned long int htonl(unsigned long int hostlong);
  5. 函数说明:htonl ()用来将参数指定的32 hostlong 转换成网络字符顺序.
  6. 返回值:返回对应的网络字符顺序.
定义函数:int inet_aton(const char *string, struct in_addr*addr);
  1.  
参数描述:
  1.  
1 输入参数string包含ASCII表示的IP地址。
  1.  
2 输出参数addr是将要用新的IP地址更新的结构。
  1.  
返回值:
  1.  
如果这个函数成功,函数的返回值非零,如果输入地址不正确则会返回零。使用这个函数并没有错误码存放在errno中,所以它的值会被忽略
  1.  

1.5 监听,封装了bind和listen实现

  1. static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
  2. if (bind(s,sa,len) == -) {        //绑定
  3. anetSetError(err, "bind: %s", strerror(errno));
  4. close(s);
  5. return ANET_ERR;
  6. }
  7.  
  8. /* Use a backlog of 512 entries. We pass 511 to the listen() call because
  9. * the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
  10. * which will thus give us a backlog of 512 entries */
  11. if (listen(s, ) == -) { //监听
  12. anetSetError(err, "listen: %s", strerror(errno));
  13. close(s);
  14. return ANET_ERR;
  15. }
  16. return ANET_OK;
  17. }

2.tcp连接建立堵塞和非堵塞网络套接字连接。

  1. int anetTcpConnect(char *err, char *addr, int port)
  2. {
  3. return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE);
  4. }
  5.  
  6. int anetTcpNonBlockConnect(char *err, char *addr, int port)
  7. {
  8. return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK);
  9. }
  10.  
  11. //具体实现
  12. #define ANET_CONNECT_NONE 0
  13. #define ANET_CONNECT_NONBLOCK 1
  14. static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
  15. {
  16. int s;
  17. struct sockaddr_in sa;
  18.  
  19. if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
  20. return ANET_ERR;
  21.  
  22. sa.sin_family = AF_INET;
  23. sa.sin_port = htons(port);
  24. if (inet_aton(addr, &sa.sin_addr) == ) {
  25. struct hostent *he;
  26.  
  27. he = gethostbyname(addr);
  28. if (he == NULL) {
  29. anetSetError(err, "can't resolve: %s", addr);
  30. close(s);
  31. return ANET_ERR;
  32. }
  33. memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
  34. }
  35. if (flags & ANET_CONNECT_NONBLOCK) {
  36. if (anetNonBlock(err,s) != ANET_OK)
  37. return ANET_ERR;
  38. }
  39. if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -) {
  40. if (errno == EINPROGRESS &&
  41. flags & ANET_CONNECT_NONBLOCK)
  42. return s;
  43.  
  44. anetSetError(err, "connect: %s", strerror(errno));
  45. close(s);
  46. return ANET_ERR;
  47. }
  48. return s;
  49. }

2.1 结构体hostent

  1. struct hostent {
  2.    char *h_name;
  3.    char **h_aliases;
  4.    int h_addrtype;
  5.    int h_length;
  6.    char **h_addr_list;
  7.    };

其中,h_name – 地址的正式名称。 
  h_aliases – 空字节-地址的预备名称的指针。 
  h_addrtype –地址类型; 通常是AF_INET。  
  h_length – 地址的比特长度。 
  h_addr_list – 零字节-主机网络地址指针。网络字节顺序。 
  h_addr - h_addr_list中的第一地址。 
gethostbyname() 成功时返回一个指向结构体 hostent 的指针,或者 是个空 (NULL) 指针。

2.2 设置非堵塞

  1. int anetNonBlock(char *err, int fd)
  2. {
  3. int flags;
  4.  
  5. /* Set the socket non-blocking.
  6. * Note that fcntl(2) for F_GETFL and F_SETFL can't be
  7. * interrupted by a signal. */
  8. if ((flags = fcntl(fd, F_GETFL)) == -) {
  9. anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));
  10. return ANET_ERR;
  11. }
  12. if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -) {
  13. anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
  14. return ANET_ERR;
  15. }
  16. return ANET_OK;
  17. }

2.3 文件控制fcntl

定义函数 int fcntl(int fd, int cmd);
  int fcntl(int fd, int cmd, long arg);
  int fcntl(int fd, int cmd, struct flock *lock);
fcntl()针对(文件)描述符提供控制.实例:
  1. int flags;
  2. /* 设置为非阻塞*/
  3. if (fcntl(socket_descriptor, F_SETFL, flags | O_NONBLOCK) < )
  4. {
  5. /* Handle error */
  6. }
  7. /* 设置为阻塞 */
  8. if ((flags = fcntl(sock_descriptor, F_GETFL, )) < )
  9. {
  10. /* Handle error */
  11. }

3. tcp接收,在网络套接字上新增连接

  1. int anetTcpAccept(char *err, int s, char *ip, int *port) {
  2. int fd;
  3. struct sockaddr_in sa;
  4. socklen_t salen = sizeof(sa);
  5. if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
  6. return ANET_ERR;
  7.  
  8. if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
  9. if (port) *port = ntohs(sa.sin_port);
  10. return fd;
  11. }

封装了accept函数

  1. static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
  2. int fd;
  3. while() {
  4. fd = accept(s,sa,len);
  5. if (fd == -) {
  6. if (errno == EINTR)
  7. continue;
  8. else {
  9. anetSetError(err, "accept: %s", strerror(errno));
  10. return ANET_ERR;
  11. }
  12. }
  13. break;
  14. }
  15. return fd;
  16. }

4. 其它方法

anetEnableTcpNoDelay:将tcp连接设为非延迟性的,即屏蔽Nagle算法。使用setsockopt方法实现。

anetDisableTcpNoDelay:和上面的方法作用相反。使用setsockopt方法实现。

anetTcpKeepAlive:开启连接检测,避免对方宕机或者网络中断时fd一直堵塞。使用setsockopt方法实现。

anetRead和anetWrite:套接字的读写。

参考资料

Redis源代码分析.pdf----未知来源

深入redis内部---网络编程的更多相关文章

  1. golang(9):网络编程 & redis

    网络编程 TCP/IP 协议: . TCP(传输控制协议) -- 应用程序之间通信 . UDP(用户数据包协议)-- 应用程序之间的简单通信 . IP(网际协议) -- 计算机之间的通信 . DHCP ...

  2. 猫哥网络编程系列:详解 BAT 面试题

    从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...

  3. Netty与网络编程

    Netty什么? Netty项目是一个提供异步事件驱动网络应用框架和快速开发可维护的高性能高扩展性服务端和客户端协议工具集的成果.换句话说,Netty是一个NIO客户端服务端框架,它使得快速而简单的开 ...

  4. 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...

  5. Java网络编程中异步编程的理解

    目录 前言 一.异步,同步,阻塞和非阻塞的理解 二.异步编程从用户层面和框架层面不同角度的理解 用户角度的理解 框架角度的理解 三.为什么使用异步 四.理解这些能在实际中的应用 六.困惑 参考文章 前 ...

  6. 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型

    进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...

  7. [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?     http://www.52im.net/thread-1732-1-1.html   1.引言 本文接上篇<脑残式网 ...

  8. python网络编程知识体系

    python的网络编程包括: 1.mvc-socket-线程-进程-并发-IO异步-消费者生产者 2.mysql-paramiko-审计堡垒机-redis-分布式监控 线程.进程 和 协程 原理剖析 ...

  9. python部分 + 数据库 + 网络编程

    PS:附上我的博客地址,答案中略的部分我的博客都有,直接原标题搜索即可.https://www.cnblogs.com/Roc-Atlantis/ 第一部分 Python基础篇(80题) 为什么学习P ...

随机推荐

  1. openedx下载汉化包的一些操作

    首先我是用debian9系统,然后装了xface桌面,感觉挺好用的,怎么确定路径是否和别人的一样了,我主要参照edx-platform这个文件夹的位置. 1. 参照大神的这个贴子https://www ...

  2. Page.FindControl(string id) 与母版页结合后发现的一个问题

    MSDN上解释Page.FindControl(string id)方法用于查找指定ID的控件.例如: <asp:TextBox id="Email" runat=" ...

  3. 如何防止Unity3D代码被反编译?

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 网易云易盾移动游戏安全技术专家陈士留在2018年Unity技术路演演讲内容中对这个问题有过比较详细的介绍,摘录如下: 防止Unity3D代码被反编译 ...

  4. oracle ocp题库变化,052最新考试题及答案整理-30

    30.Which is true when a database instance is shut down? A. Only transactional and normal modes wait ...

  5. kvm虚拟机静态迁移

    1.静态迁移就是虚拟机在关机状态下,拷贝虚拟机虚拟磁盘文件与配置文件到目标虚拟主机中,实现的迁移. (1)虚拟主机各自使用本地存储存放虚拟机磁盘文件 本文实现基于本地磁盘存储虚拟机磁盘文件的迁移方式, ...

  6. 洛谷P4337 [ZJOI2018]线图(状压+搜索+乱搞)

    题面 传送门 题解 妈呀调了我整整一天-- 题解太长了不写了可以去看\(shadowice\)巨巨的 //minamoto #include<bits/stdc++.h> #define ...

  7. SP16580 QTREE7 - Query on a tree VII(LCT)

    题意翻译 一棵树,每个点初始有个点权和颜色(输入会给你) 0 u:询问所有u,v路径上的最大点权,要满足u,v路径上所有点颜色相同 1 u:反转u的颜色 2 u w:把u的点权改成w 题解 Qtree ...

  8. Squid代理服务器(二)——配置Squid服务器

    一.传统代理 (一)需求分析 局域网内,客户机访问自家的Web服务器,通过Squid代理服务器访问Web服务器,再由Squid反馈给客户机;在Squid主机上,构建Squid为客户机访问网站提供代理服 ...

  9. sqlalchemy 常用总结

    mysql-5.7安装 https://blog.csdn.net/since_1904/article/details/70233403 flask-sqlalchemy教程 http://www. ...

  10. 【Python】批量检测百度权重

    挖洞过程中收集了站点后,我一般习惯查看站点的百度权重值,为了方便,写了一个简单的脚本, 至于结果如何显示,看个人需求吧,我这里只是简单的列一下,脚本如下: #coding:utf-8 import r ...