深入redis内部---网络编程
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表示使用IPv4return 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) == 0) {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_instruct sockaddr_in {short int sin_family; // Address familyunsigned short int sin_port; // Port numberstruct in_addr sin_addr; // Internet addressunsigned char sin_zero[8]; // Same size as struct sockaddr};1.2 创建socket,封装了socket实现static int anetCreateSocket(char *err, int domain) {int s, on = 1;if ((s = socket(domain, SOCK_STREAM, 0)) == -1) { //创建socketanetSetError(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)) == -1) { //设置选项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) == -1) {//绑定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, 511) == -1) { //监听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 1static 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) == 0) {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)) == -1) {if (errno == EINPROGRESS &&flags & ANET_CONNECT_NONBLOCK)return s;anetSetError(err, "connect: %s", strerror(errno));close(s);return ANET_ERR;}return s;}2.1 结构体hostentstruct 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)) == -1) {anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));return ANET_ERR;}if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {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) < 0){/* Handle error */}/* 设置为阻塞 */if ((flags = fcntl(sock_descriptor, F_GETFL, 0)) < 0){/* 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;i