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

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

int anetTcpServer(char *err, int port, char *bindaddr)
{
int s;
struct sockaddr_in sa;                          //见1.1结构体 if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR) //AF_INET表示使用IPv4
return ANET_ERR; memset(&sa,0,sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == ) {
anetSetError(err, "invalid bind address");
close(s);
return ANET_ERR;
}
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
return ANET_ERR;
return s;
}

1.1 结构体sockaddr_in

    struct sockaddr_in {
short int sin_family; // Address family
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[]; // Same size as struct sockaddr
};

1.2 创建socket,封装了socket实现

static int anetCreateSocket(char *err, int domain) {
int s, on = ;
if ((s = socket(domain, SOCK_STREAM, )) == -) { //创建socket
anetSetError(err, "creating socket: %s", strerror(errno));
return ANET_ERR;
} /* Make sure connection-intensive things like the redis benchmark
* will be able to close/open sockets a zillion of times */
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -) { //设置选项
anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
return ANET_ERR;
}
return s;
}

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>
定义函数:unsigned short int htons(unsigned short int hostshort);

函数说明:htons()用来将参数指定的16 位hostshort 转换成网络字符顺序.

返回值:返回对应的网络字符顺序.

定义函数:unsigned long int htonl(unsigned long int hostlong);
函数说明:htonl ()用来将参数指定的32 位hostlong 转换成网络字符顺序. 返回值:返回对应的网络字符顺序.
定义函数:int inet_aton(const char *string, struct in_addr*addr);

参数描述:

1 输入参数string包含ASCII表示的IP地址。

2 输出参数addr是将要用新的IP地址更新的结构。

返回值:

如果这个函数成功,函数的返回值非零,如果输入地址不正确则会返回零。使用这个函数并没有错误码存放在errno中,所以它的值会被忽略
 

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

static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
if (bind(s,sa,len) == -) {        //绑定
anetSetError(err, "bind: %s", strerror(errno));
close(s);
return ANET_ERR;
} /* Use a backlog of 512 entries. We pass 511 to the listen() call because
* the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
* which will thus give us a backlog of 512 entries */
if (listen(s, ) == -) { //监听
anetSetError(err, "listen: %s", strerror(errno));
close(s);
return ANET_ERR;
}
return ANET_OK;
}

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

int anetTcpConnect(char *err, char *addr, int port)
{
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE);
} int anetTcpNonBlockConnect(char *err, char *addr, int port)
{
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK);
} //具体实现
#define ANET_CONNECT_NONE 0
#define ANET_CONNECT_NONBLOCK 1
static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
{
int s;
struct sockaddr_in sa; if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
return ANET_ERR; sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if (inet_aton(addr, &sa.sin_addr) == ) {
struct hostent *he; he = gethostbyname(addr);
if (he == NULL) {
anetSetError(err, "can't resolve: %s", addr);
close(s);
return ANET_ERR;
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
}
if (flags & ANET_CONNECT_NONBLOCK) {
if (anetNonBlock(err,s) != ANET_OK)
return ANET_ERR;
}
if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -) {
if (errno == EINPROGRESS &&
flags & ANET_CONNECT_NONBLOCK)
return s; anetSetError(err, "connect: %s", strerror(errno));
close(s);
return ANET_ERR;
}
return s;
}

2.1 结构体hostent

struct hostent {
   char *h_name;
   char **h_aliases;
   int h_addrtype;
   int h_length;
   char **h_addr_list;
   };

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

2.2 设置非堵塞

int anetNonBlock(char *err, int fd)
{
int flags; /* Set the socket non-blocking.
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
* interrupted by a signal. */
if ((flags = fcntl(fd, F_GETFL)) == -) {
anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));
return ANET_ERR;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -) {
anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
return ANET_ERR;
}
return ANET_OK;
}

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()针对(文件)描述符提供控制.实例:
int flags;
/* 设置为非阻塞*/
if (fcntl(socket_descriptor, F_SETFL, flags | O_NONBLOCK) < )
{
/* Handle error */
}
/* 设置为阻塞 */
if ((flags = fcntl(sock_descriptor, F_GETFL, )) < )
{
/* Handle error */
}

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

int anetTcpAccept(char *err, int s, char *ip, int *port) {
int fd;
struct sockaddr_in sa;
socklen_t salen = sizeof(sa);
if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
return ANET_ERR; if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
if (port) *port = ntohs(sa.sin_port);
return fd;
}

封装了accept函数

static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
int fd;
while() {
fd = accept(s,sa,len);
if (fd == -) {
if (errno == EINTR)
continue;
else {
anetSetError(err, "accept: %s", strerror(errno));
return ANET_ERR;
}
}
break;
}
return fd;
}

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. Verilog MIPS32 CPU(八)-- 控制器

    Verilog MIPS32 CPU(一)-- PC寄存器 Verilog MIPS32 CPU(二)-- Regfiles Verilog MIPS32 CPU(三)-- ALU Verilog M ...

  2. c# winform实现同时只允许账号在一台电脑登录的功能

    公司有个小需求,要求账号不能同时登录在多台电脑上,就像那个微信或QQ一样,如果一台电脑登录了,原来登录的就自动退出了(网上搜索点单点登录,发现有些出入,人家是实现一次登录在多个系统间认证的) 找了些资 ...

  3. Spring Boot专题背景简介

    鄙人13年毕业,不曾在圈子里写过总结,因此文笔颇不自信. 但人生永远没有太晚的开始,现在开始做些笔记,借此巩固下学到的新知识. 一些题外话: 前段时间,做个小项目,由于某些原因,使用Java来写(之前 ...

  4. C#里面获得应用程序的当前路径

    在C#里面获得应用程序的当前路径 Environment.CurrentDirectorySystem.IO.Directory.GetCurrentDirectory() ——上面两种获得的是当前路 ...

  5. GridView中文属性

    GridControl的中文属性: 1  Appearance 外观 Appearance 外观设置 ColumnFilterButton  行过滤器按钮 BackerColor  背景色 Backe ...

  6. Visual Studio 2008 SP1键盘F10单步调试超慢解决方法

    症状: 中断程序调试时,F10或者其它键盘操作都超级慢. 鼠标点击工具栏的按钮速度正常. 解决方法: 网上说的什么删掉所有断点啦,关掉几个窗口啦,重置用户设置啦,关掉某某调试选项啦,关掉防火墙啦,都是 ...

  7. [Flex] 组件Tree系列 —— 将数组作为dataProvider

    mxml: <?xml version="1.0" encoding="utf-8"?> <!--功能描述:将数组作为dataProvider ...

  8. 使用git提交代码简单说明

    一. 图形化git 1.首先下载msysgit,和 tortoisegit, 先装msysgit再装小乌龟 2.运行git按照github上说明生成秘钥对     ssh-keygen -t rsa ...

  9. Python3学习札记

    1.- (按位取反) x的按位取反结果为-(x+1)   e.g. -5输出-6 更多细节,阅:http://stackoverflow.com/a/11810203 2.DocString约定 为一 ...

  10. Scrapy 抓取股票行情

    安装scrapy会出现错误,我们选择anaconda3作为编译环境,搜索scrapy安装(有错误自查) 创建scrapy爬虫项目: 调出cmd,到相应目录:输入: scrapy startprojec ...