加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-16 04:45:06 所属栏目:安全 来源:网络整理
导读:Redis在anet.h和anet.c中封装了底层套接字实现: 1.anetTcpServer,建立网络套接字服务器,完成对socket(),bind(),listen()等操作的封装,返回socket的fd。 anetTcpServer( *err, port, * sa; //见1.1结构体 /spanspan style="color: #0000ff;"gt;if/span ((

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,)) == -</span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; 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;"&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: %s</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>
htons(unsigned 函数说明:htons()用来将参数指定的16 位hostshort 转换成网络字符顺序.

返回值:返回对应的网络字符顺序.
定义函数: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实现

anetListen( *err, s, sockaddr * (bind(s,sa,len) == -</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: %s</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: %s</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;
    }
    memcpy(</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: %s</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): %s</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): %s</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

(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) strcpy(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 ==

4. 其它方法

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

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

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

? anetRead和anetWrite:套接字的读写。

?参考资料

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读