Redis在anet.h和anet.c中封装了底层套接字实现:
1.anetTcpServer,建立网络套接字服务器,完成对socket(),bind(),listen()等操作的封装,返回socket的fd。
</span><span style="color: #0000ff;">if</span> ((s = <span style="color: #ff0000;">anetCreateSocket</span>(err,AF_INET)) ==<span style="color: #000000;"> ANET_ERR) //AF_INET表示使用IPv4
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
<span style="color: #ff0000;">memset(</span></span><span style="color: #ff0000;">&sa,sizeof</span><span style="color: #000000;"><span style="color: #ff0000;">(sa))</span>;
sa.sin_family </span>=<span style="color: #000000;"> AF_INET;
sa.sin_port </span>=<span style="color: #000000;"><span style="color: #ff0000;"> htons</span>(port);
sa.sin_addr.s_addr </span>=<span style="color: #000000;"><span style="color: #ff0000;"> htonl</span>(INADDR_ANY);
</span><span style="color: #0000ff;">if</span> (bindaddr && <span style="color: #ff0000;">inet_aton</span>(bindaddr,&sa.sin_addr) == <span style="color: #800080;">0</span><span style="color: #000000;">) {
anetSetError(err,</span><span style="color: #800000;">"</span><span style="color: #800000;">invalid bind address</span><span style="color: #800000;">"</span><span style="color: #000000;">);
close(s);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
}
</span><span style="color: #0000ff;">if</span> (<span style="color: #ff0000;">anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)</span>) ==<span style="color: #000000;"> ANET_ERR)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> s;
}
1.1 结构体sockaddr_in
1.2 创建socket,封装了socket实现
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> Make sure connection-intensive things like the redis benchmark
* will be able to close/open sockets a zillion of times </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&on,<span style="color: #0000ff;">sizeof</span>(on)) == -<span style="color: #800080;">1</span><span style="color: #000000;">) { //设置选项
anetSetError(err,</span><span style="color: #800000;">"</span><span style="color: #800000;">setsockopt SO_REUSEADDR: %s</span><span style="color: #800000;">"</span><span style="color: #000000;">,strerror(errno));
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> s;
}
1.3 memset函数
在C中
返回值:返回对应的网络字符顺序.
定义函数:unsigned long int htonl(unsigned long int hostlong);函数说明:htonl ()用来将参数指定的32 位hostlong 转换成网络字符顺序.返回值:返回对应的网络字符顺序.
<div class="para">定义函数:int inet_aton(const char string,struct <a href="http://baike.baidu.com/view/2907631.htm" target="_blank">in_addraddr);
1.5 监听,封装了bind和listen实现
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> 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 </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (listen(s,<span style="color: #800080;">511</span>) == -<span style="color: #800080;">1</span><span style="color: #000000;">) { //监听
anetSetError(err,</span><span style="color: #800000;">"</span><span style="color: #800000;">listen: %s</span><span style="color: #800000;">"</span><span style="color: #000000;">,strerror(errno));
close(s);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_OK;
}
2.tcp连接建立堵塞和非堵塞网络套接字连接。
} <span style="color: #008000;">//<span style="color: #008000;">具体实现
<span style="color: #0000ff;">#define ANET_CONNECT_NONE 0
<span style="color: #0000ff;">#define ANET_CONNECT_NONBLOCK 1
<span style="color: #0000ff;">static <span style="color: #0000ff;">int anetTcpGenericConnect(<span style="color: #0000ff;">char *err,<span style="color: #0000ff;">int<span style="color: #000000;"> flags)
{
<span style="color: #0000ff;">int<span style="color: #000000;"> s;
<span style="color: #0000ff;">struct<span style="color: #000000;"> sockaddr_in sa;
</span><span style="color: #0000ff;">if</span> ((s = anetCreateSocket(err,AF_INET)) ==<span style="color: #000000;"> ANET_ERR)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
sa.sin_family </span>=<span style="color: #000000;"> AF_INET;
sa.sin_port </span>=<span style="color: #000000;"> htons(port);
</span><span style="color: #0000ff;">if</span> (inet_aton(addr,&sa.sin_addr) == <span style="color: #800080;">0</span><span style="color: #000000;">) {
</span><span style="color: #0000ff;">struct</span> hostent *<span style="color: #000000;">he;
he </span>=<span style="color: #000000;"> gethostbyname(addr);
</span><span style="color: #0000ff;">if</span> (he ==<span style="color: #000000;"> NULL) {
anetSetError(err,</span><span style="color: #800000;">"</span><span style="color: #800000;">can't resolve: %s</span><span style="color: #800000;">"</span><span style="color: #000000;">,addr);
close(s);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
}
memcpy(</span>&sa.sin_addr,he->h_addr,<span style="color: #0000ff;">sizeof</span>(<span style="color: #0000ff;">struct</span><span style="color: #000000;"> in_addr));
}
</span><span style="color: #0000ff;">if</span> (flags &<span style="color: #000000;"> ANET_CONNECT_NONBLOCK) {
</span><span style="color: #0000ff;">if</span> (<span style="color: #ff0000;">anetNonBlock</span>(err,s) !=<span style="color: #000000;"> ANET_OK)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
}
</span><span style="color: #0000ff;">if</span> (connect(s,(<span style="color: #0000ff;">struct</span> sockaddr*)&sa,<span style="color: #0000ff;">sizeof</span>(sa)) == -<span style="color: #800080;">1</span><span style="color: #000000;">) {
</span><span style="color: #0000ff;">if</span> (errno == EINPROGRESS &&<span style="color: #000000;">
flags </span>&<span style="color: #000000;"> ANET_CONNECT_NONBLOCK)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> s;
anetSetError(err,</span><span style="color: #800000;">"</span><span style="color: #800000;">connect: %s</span><span style="color: #800000;">"</span><span style="color: #000000;">,strerror(errno));
close(s);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> s;
}
2.1 结构体hostent
其中,h_name – 地址的正式名称。 h_aliases – 空字节-地址的预备名称的指针。 h_addrtype –地址类型; 通常是AF_INET。 h_length – 地址的比特长度。 h_addr_list – 零字节-主机网络地址指针。网络字节顺序。 h_addr - h_addr_list中的第一地址。 gethostbyname() 成功时返回一个指向结构体 hostent 的指针,或者 是个空 (NULL) 指针。
2.2 设置非堵塞
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> Set the socket non-blocking.
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
* interrupted by a signal. </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> ((flags = <span style="color: #ff0000;">fcntl</span>(fd,F_GETFL)) == -<span style="color: #800080;">1</span><span style="color: #000000;">) {
anetSetError(err,</span><span style="color: #800000;">"</span><span style="color: #800000;">fcntl(F_GETFL): %s</span><span style="color: #800000;">"</span><span style="color: #000000;">,strerror(errno));
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
}
</span><span style="color: #0000ff;">if</span> (fcntl(fd,F_SETFL,flags | O_NONBLOCK) == -<span style="color: #800080;">1</span><span style="color: #000000;">) {
anetSetError(err,</span><span style="color: #800000;">"</span><span style="color: #800000;">fcntl(F_SETFL,O_NONBLOCK): %s</span><span style="color: #800000;">"</span><span style="color: #000000;">,strerror(errno));
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_ERR;
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ANET_OK;
}
2.3 文件控制fcntl
3. tcp接收,在网络套接字上新增连接
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
</span><span style="color: #0000ff;">if</span> (port) *port =<span style="color: #000000;"> ntohs(sa.sin_port);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> fd;
}
封装了accept函数
4. 其它方法
anetEnableTcpNoDelay:将tcp连接设为非延迟性的,即屏蔽Nagle算法。使用setsockopt方法实现。
anetDisableTcpNoDelay:和上面的方法作用相反。使用setsockopt方法实现。
anetTcpKeepAlive:开启连接检测,避免对方宕机或者网络中断时fd一直堵塞。使用setsockopt方法实现。
anetRead和anetWrite:套接字的读写。
参考资料
Redis源代码分析.pdf----未知来源