微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

深入redis内部---网络编程

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

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

anetTcpserver( *err, port, * sa;                          //见1.1结构体
</span><span style="color: #0000ff;"&gt;if</span> ((s = <span style="color: #ff0000;"&gt;anetCreateSocket</span>(err,AF_INET)) ==<span style="color: #000000;"&gt; ANET_ERR)               //AF_INET表示使用IPv4
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR;

<span style="color: #ff0000;"&gt;memset(</span></span><span style="color: #ff0000;"&gt;&amp;sa,sizeof</span><span style="color: #000000;"&gt;<span style="color: #ff0000;"&gt;(sa))</span>;
sa.sin_family </span>=<span style="color: #000000;"&gt; AF_INET;
sa.sin_port </span>=<span style="color: #000000;"&gt;<span style="color: #ff0000;"&gt; htons</span>(port);
sa.sin_addr.s_addr </span>=<span style="color: #000000;"&gt;<span style="color: #ff0000;"&gt; htonl</span>(INADDR_ANY);
</span><span style="color: #0000ff;"&gt;if</span> (bindaddr &amp;&amp; <span style="color: #ff0000;"&gt;inet_aton</span>(bindaddr,&amp;sa.sin_addr) == <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;) {
    anetSetError(err,</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;invalid bind address</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;);
    close(s);
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR;
}
</span><span style="color: #0000ff;"&gt;if</span> (<span style="color: #ff0000;"&gt;anetListen(err,s,(struct sockaddr*)&amp;sa,sizeof(sa)</span>) ==<span style="color: #000000;"&gt; ANET_ERR)
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR;
</span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; s;

}

 1.1 结构体sockaddr_in

sin_family; unsigned sin_port; in_addr sin_addr; unsigned sin_zero[]; };

1.2 创建socket,封装了socket实现

anetCreateSocket( *err, s,on = ((s = socket(domain,SOCK_STREAM,)) == -%s</span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; Make sure connection-intensive things like the re<a href="/tag/dis/" target="_blank" class="keywords">dis</a> benchmark * will be able to close/open sockets a zillion of times </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&amp;on,<span style="color: #0000ff;"&gt;sizeof</span>(on)) == -<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;) { //设置选项 anetSetError(err,</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;setsockopt SO_REUSEADDR: <a href="/tag/s/" target="_blank" class="keywords">%s</a></span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,strerror(errno)); </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR; } </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; s;

}

1.3 memset函数

在C中 ,原型为:void *memset(void *s,int ch, n);

.h>


ara">参数描述:

ara">1 输入参数string包含表示的IP地址。



存放在errno中,所以它的值会被忽略

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

anetListen( *err, s, sockaddr * (bind(s,sa,len) == -%s</span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; 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;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (listen(s,<span style="color: #800080;"&gt;511</span>) == -<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;) { //监听 anetSetError(err,</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;listen: <a href="/tag/s/" target="_blank" class="keywords">%s</a></span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,strerror(errno)); close(s); </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR; } </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_OK;

}

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

anetTcpConnect( *err, *addr,<span style="color: #0000ff;">int anetTcpNonBlockConnect(<span style="color: #0000ff;">char *err,ANET_CONNECT_NONBLOCK);
}

<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;"&gt;if</span> ((s = anetCreateSocket(err,AF_INET)) ==<span style="color: #000000;"&gt; ANET_ERR)
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR;

sa.sin_family </span>=<span style="color: #000000;"&gt; AF_INET;
sa.sin_port </span>=<span style="color: #000000;"&gt; htons(port);
</span><span style="color: #0000ff;"&gt;if</span> (inet_aton(addr,&amp;sa.sin_addr) == <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;) {
    </span><span style="color: #0000ff;"&gt;struct</span> hostent *<span style="color: #000000;"&gt;he;

    he </span>=<span style="color: #000000;"&gt; gethostbyname(addr);
    </span><span style="color: #0000ff;"&gt;if</span> (he ==<span style="color: #000000;"&gt; NULL) {
        anetSetError(err,</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;can't resolve: <a href="/tag/s/" target="_blank" class="keywords">%s</a></span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,addr);
        close(s);
        </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR;
    }
    mem<a href="/tag/cpy/" target="_blank" class="keywords">cpy</a>(</span>&amp;sa.sin_addr,he->h_addr,<span style="color: #0000ff;"&gt;sizeof</span>(<span style="color: #0000ff;"&gt;struct</span><span style="color: #000000;"&gt; in_addr));
}
</span><span style="color: #0000ff;"&gt;if</span> (flags &amp;<span style="color: #000000;"&gt; ANET_CONNECT_NONBLOCK) {
    </span><span style="color: #0000ff;"&gt;if</span> (<span style="color: #ff0000;"&gt;anetNonBlock</span>(err,s) !=<span style="color: #000000;"&gt; ANET_OK)
        </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR;
}
</span><span style="color: #0000ff;"&gt;if</span> (connect(s,(<span style="color: #0000ff;"&gt;struct</span> sockaddr*)&amp;sa,<span style="color: #0000ff;"&gt;sizeof</span>(sa)) == -<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;) {
    </span><span style="color: #0000ff;"&gt;if</span> (errno == EINPROGRESS &amp;&amp;<span style="color: #000000;"&gt;
        flags </span>&amp;<span style="color: #000000;"&gt; ANET_CONNECT_NONBLOCK)
        </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; s;

    anetSetError(err,</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;connect: <a href="/tag/s/" target="_blank" class="keywords">%s</a></span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,strerror(errno));
    close(s);
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR;
}
</span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; 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 设置非堵塞

anetNonBlock( *err,</span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; 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;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> ((flags = <span style="color: #ff0000;"&gt;fcntl</span>(fd,F_GETFL)) == -<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;) { anetSetError(err,</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;fcntl(F_GETFL): <a href="/tag/s/" target="_blank" class="keywords">%s</a></span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,strerror(errno)); </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR; } </span><span style="color: #0000ff;"&gt;if</span> (fcntl(fd,F_SETFL,flags | O_NONBLOCK) == -<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;) { anetSetError(err,</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;fcntl(F_SETFL,O_NONBLOCK): <a href="/tag/s/" target="_blank" class="keywords">%s</a></span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,strerror(errno)); </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_ERR; } </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ANET_OK;

}

2.3 文件控制fcntl

ara">定义函数 int fcntl(int fd,int cmd);   int fcntl(int fd,int cmd,long arg);   int fcntl(int fd,struct flock *lock);
ara">fcntl()针对(文件)描述符提供控制.实例:
ara">
(fcntl(socket_descriptor,flags | O_NONBLOCK) < ((flags = fcntl(sock_descriptor,F_GETFL,)) <

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

anetTcpAccept( *err, *ip, *= ((fd = (err,&salen)) ==</span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; (ip) str<a href="/tag/cpy/" target="_blank" class="keywords">cpy</a>(ip,inet_ntoa(sa.sin_addr)); </span><span style="color: #0000ff;"&gt;if</span> (port) *port =<span style="color: #000000;"&gt; ntohs(sa.sin_port); </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; fd;

}

封装了accept函数

anetGenericAccept( *err, sockaddr *sa,socklen_t *(= (fd == - (errno ==%s

4. 其它方法

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

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

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

  anetRead和anetWrite:套接字的读写。

 参考资料

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐