日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時(shí)間:2025/4/5 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入redis内部---网络编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Redis在anet.h和anet.c中封裝了底層套接字實(shí)現(xiàn):

1.anetTcpServer,建立網(wǎng)絡(luò)套接字服務(wù)器,完成對(duì)socket(),bind(),listen()等操作的封裝,返回socket的fd。

int anetTcpServer(char *err, int port, char *bindaddr) {int s;struct sockaddr_in sa;                          //見1.1結(jié)構(gòu)體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 結(jié)構(gòu)體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[8]; // Same size as struct sockaddr };

1.2 創(chuàng)建socket,封裝了socket實(shí)現(xiàn)

static int anetCreateSocket(char *err, int domain) {int s, on = 1;if ((s = socket(domain, SOCK_STREAM, 0)) == -1) { //創(chuàng)建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) { //設(shè)置選項(xiàng)anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));return ANET_ERR;}return s; }

1.3 memset函數(shù)

在C中 <string.h>,原型為:void *memset(void *s, int ch, size_t n);

作用:將s中前n個(gè)字節(jié) (typedef unsigned int size_t)用 ch 替換并返回 s 。 memset:作用是在一段內(nèi)存塊中填充某個(gè)給定的值,它是對(duì)較大的結(jié)構(gòu)體或數(shù)組進(jìn)行清零操作的一種最快方法。 1.4 網(wǎng)絡(luò)轉(zhuǎn)頭文件: #include <netinet/in.h> 定義函數(shù):unsigned short int htons(unsigned short int hostshort);函數(shù)說明:htons()用來將參數(shù)指定的16 位hostshort 轉(zhuǎn)換成網(wǎng)絡(luò)字符順序.返回值:返回對(duì)應(yīng)的網(wǎng)絡(luò)字符順序.

定義函數(shù):unsigned long int htonl(unsigned long int hostlong);
函數(shù)說明:htonl ()用來將參數(shù)指定的32 位hostlong 轉(zhuǎn)換成網(wǎng)絡(luò)字符順序.

返回值:返回對(duì)應(yīng)的網(wǎng)絡(luò)字符順序.


定義函數(shù):int inet_aton(const char *string, struct in_addr*addr); 參數(shù)描述: 1 輸入?yún)?shù)string包含ASCII表示的IP地址。 2 輸出參數(shù)addr是將要用新的IP地址更新的結(jié)構(gòu)。 返回值: 如果這個(gè)函數(shù)成功,函數(shù)的返回值非零,如果輸入地址不正確則會(huì)返回零。使用這個(gè)函數(shù)并沒有錯(cuò)誤碼存放在errno中,所以它的值會(huì)被忽略 ?

1.5 監(jiān)聽,封裝了bind和listen實(shí)現(xiàn)

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) { //監(jiān)聽anetSetError(err, "listen: %s", strerror(errno));close(s);return ANET_ERR;}return ANET_OK; }

?2.tcp連接建立堵塞和非堵塞網(wǎng)絡(luò)套接字連接。

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); }//具體實(shí)現(xiàn) #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) == 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 結(jié)構(gòu)體hostent

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

其中,h_name?–?地址的正式名稱。?
  h_aliases?–?空字節(jié)-地址的預(yù)備名稱的指針。?
  h_addrtype?–地址類型;?通常是AF_INET。??
  h_length?–?地址的比特長度。?
  h_addr_list?–?零字節(jié)-主機(jī)網(wǎng)絡(luò)地址指針。網(wǎng)絡(luò)字節(jié)順序。?
  h_addr?-?h_addr_list中的第一地址。?
gethostbyname()?成功時(shí)返回一個(gè)指向結(jié)構(gòu)體?hostent?的指針,或者?是個(gè)空?(NULL)?指針。

2.2 設(shè)置非堵塞

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

定義函數(shù) int fcntl(int fd, int cmd);
  int fcntl(int fd, int cmd, long arg);
  int fcntl(int fd, int cmd, struct flock *lock); fcntl()針對(duì)(文件)描述符提供控制.實(shí)例: int flags; /* 設(shè)置為非阻塞*/ if (fcntl(socket_descriptor, F_SETFL, flags | O_NONBLOCK) < 0) { /* Handle error */ } /* 設(shè)置為阻塞 */ if ((flags = fcntl(sock_descriptor, F_GETFL, 0)) < 0) { /* Handle error */ }

3. tcp接收,在網(wǎng)絡(luò)套接字上新增連接

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函數(shù)

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

4. 其它方法

? anetEnableTcpNoDelay:將tcp連接設(shè)為非延遲性的,即屏蔽Nagle算法。使用setsockopt方法實(shí)現(xiàn)。

??anetDisableTcpNoDelay:和上面的方法作用相反。使用setsockopt方法實(shí)現(xiàn)。

? anetTcpKeepAlive:開啟連接檢測(cè),避免對(duì)方宕機(jī)或者網(wǎng)絡(luò)中斷時(shí)fd一直堵塞。使用setsockopt方法實(shí)現(xiàn)。

? anetRead和anetWrite:套接字的讀寫。

?參考資料

Redis源代碼分析.pdf----未知來源

轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/3516489.html

總結(jié)

以上是生活随笔為你收集整理的深入redis内部---网络编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。