From:?http://blog.csdn.net/jasonliuvip/article/details/22591531
最近在看《linux高性能服務器編程》,在此做個日記,以激勵自己,同時分享于有需要的朋友。
1. 讀取和設置socket文件描述符屬性:
[cpp]?view plaincopy
#include?<sys/socket.h>?? ?? int?getsockopt(int?sockfd,?int?level,?int?option_name,?void?*option_value,?socklen_t?*restrict?option_len);?? ?? int?setsockopt(int?sockfd,?int?level,?int?option_name,?const?void?*option_value,?socklen_t?option_len);??
sockfd參數指定被操作的目標socket。?
level參數指定要操作哪個協議的選項,即屬性,比如:IPv4, IPv6, TCP 和通用socket選項。
option_name參數指定選項的名字。
option_value參數指定選項的值。
option_len參參數指定選項的長度。
調用成功時返回0, 失敗時返回-1, 并設置errno。
2. 對服務器而言,有部分socket選項只能在調用listen前設置才會有效。因為連接socket只能由accept調用返回,而accept從listen監聽隊列中接受的連接至少已經完成了TCP三次握手的前兩個步聚,listen監聽隊列的連接至少已進入SYN_RCVD狀態,這時服務器已經往被連接上發送TCP同步報文。
3. SO_REUSeADDR選項:重用本地地址
未設置此項前,若服務端開啟后,又關閉,此時sock處于TIME_WAIT狀態,與之綁定的socket地址不可重用,而導致再次開啟服務端失敗。
經過setsockopt設置之后, 即使處于TIME_WAIT些狀態也可以立即被重用。
[cpp]?view plaincopy
int?reuse?=?1;?? setsockopt(sock,?SOL_SOCKET,?SO_REUSEADDR,?&reuse,?sizof(reuse));??
4. SO_RCVBUF 和 SO_SNDBUF :TCP接收緩沖區和發送緩沖區的大小
當然,即使我們設置了這兩項的大小時, 系統都會自動將其加倍, 并且不得小于某個最小值。
TCP接收緩沖區的最小值是 256 字節, 而發送緩沖區的最小值是 2048 字節。(不同系統可能會有差異)
這么做的目的是確保一個TCP連接擁有足夠多的空閑緩沖區來處理擁塞。
[java]?view plaincopy
setsockopt(sock,?SOL_SOCKET,?SO_SNDBUF,?&sendbuf,?sizeof(sendbuf));?? getsockopt(sock,?SOL_SOCKET,?SO_SNDBUF,?&sendbuf,?(socklen_t*)&len);?? ?? setsockopt(sock,?SOL_SOCKET,?SO_RCVBUF,?&recvbuf,?sizeof(recvbuf));?? getsockopt(sock,?SOL_SOCKET,?SO_RCVBUF,?&recvbuf,?(socklen_t*)&len);??
5. 代碼
[cpp]?view plaincopy
?? #include?<stdio.h>?? #include?<stdlib.h>?? #include?<unistd.h>?? #include?<string.h>?? #include?<errno.h>?? #include?<sys/socket.h>?? #include?<arpa/inet.h>?? #include?<assert.h>?? ?? #define?BUFFER_SIZE?1024?? ?? int?main(int?argc,?char?**argv)?? {?? ????if?(argc?<=?3)?{?? ????????printf("Usage:?%s?ip?port?revc_size\n",?basename(argv[0]));?? ????????return?1;?? ????}?? ?????? ????const?char?*ip?=?argv[1];?? ????int?port?=?atoi(argv[2]);?? ?????? ????struct?sockaddr_in?address;?? ????bzero(&address,?sizeof(address));?? ????address.sin_family?=?AF_INET;?? ????address.sin_port?=?htons(port);?? ????inet_pton(AF_INET,?ip,?&address.sin_addr);?? ?????? ????int?sock?=?socket(PF_INET,?SOCK_STREAM,?0);?? ????assert(sock?>=?0);?? ?? ?????????? ????int?reuse?=?1;?? ????setsockopt(sock,?SOL_SOCKET,?SO_REUSEADDR,?&reuse,?sizof(reuse));?? ?????? ????int?recvbuf?=?atoi(argv[3]);?? ????int?len?=?sizeof(recvbuf);?? ?????? ?????????? ????setsockopt(sock,?SOL_SOCKET,?SO_RCVBUF,?&recvbuf,?sizeof(recvbuf));?? ?????????? ????????getsockopt(sock,?SOL_SOCKET,?SO_RCVBUF,?&recvbuf,?(socklen_t*)&len);?? ????printf("the?receive?buffer?size?after?setting?is?%d\n",?recvbuf);?? ?????? ????int?ret?=?bind(sock,?(struct?sockaddr*)&address,?sizeof(address));?? ????assert(ret?!=?-1);?? ?????? ????ret?=?listen(sock,?5);?? ????assert(ret?!=?-1);?? ?????? ????struct?sockaddr_in?client;?? ????socklen_t?client_addrlength?=?sizeof(client);?? ?????? ????int?connfd?=?accept(sock,?(struct?sockaddr*)&client,?&client_addrlength);?? ????if?(connfd?<?0)?{?? ????????printf("errno?is:?%d\n",?errno);?? ????}?? ????else?{?? ????????char?buffer[BUFFER_SIZE];?? ????????memset(buffer,?'\0',?BUFFER_SIZE);?? ?????????? ????????while?(recv(connfd,?buffer,?BUFFER_SIZE-1,?0)?>?0);?? ?????????? ????????printf("recv:?%s\n",?buffer);?? ????????close(connfd);?? ????}?? ?????? ????close(sock);?? ?????? ????return?0;?? }??
運行后:
jason@lightning:~/myproject/test_recv$ ./test_recv localhost 8000 50
the receive buffer size after setting is 2280
很明顯被修改過了, 我們給的50, 被改為2280。
[cpp]?view plaincopy
?? #include?<stdio.h>?? #include?<sys/socket.h>?? #include?<arpa/inet.h>?? #include?<assert.h>?? #include?<unistd.h>?? #include?<stdlib.h>?? #include?<string.h>?? ?? #define?BUFFER_SIZE?1024?? ?? int?main(int?argc,?char?**argv)?? {?? ????if(argc?<=?3)?{?? ????????fprintf(stderr,?"Usage:?%s?ip?port?send_buffer_size\n",??? ????????????????basename(argv[0]));?? ????????return?1;?? ????}?? ?????? ????const?char?*ip?=?argv[1];?? ????int?port?=?atoi(argv[2]);?? ?????? ????struct?sockaddr_in?server_address;?? ????bzero(&server_address,?sizeof(server_address));?? ????server_address.sin_family?=?AF_INET;?? ????server_address.sin_port?=?htons(port);?? ????inet_pton(AF_INET,?ip,?&server_address.sin_addr);?? ?? ????int?sock?=?socket(PF_INET,?SOCK_STREAM,?0);?? ????assert(sock?>=?0);?? ?????? ????int?sendbuf?=?atoi(argv[3]);?? ????int?len?=?sizeof(sendbuf);?? ?????? ?????????? ????setsockopt(sock,?SOL_SOCKET,?SO_SNDBUF,?&sendbuf,?sizeof(sendbuf));?? ?????????? ????????getsockopt(sock,?SOL_SOCKET,?SO_SNDBUF,?&sendbuf,?(socklen_t*)&len);?? ?????? ????printf("the?tcp?send?buffer?size?after?setting?is?%d\n",?? ????????????sendbuf);?? ?????? ????if?(connect(sock,?(struct?sockaddr*)&server_address,?sizeof(server_address))?!=?-1)?{?? ????????char?buffer[BUFFER_SIZE];?? ????????memset(buffer,?'a',?BUFFER_SIZE);?? ????????send(sock,?buffer,?BUFFER_SIZE,?0);?? ????}?? ????else?{?? ????????printf("connect?%s?failed\n",?ip);?? ????}?? ?????? ????close(sock);?? ?????? ????return?0;?? }??
運行后:
jason@lightning:~/myproject/test_send$ ./test_send localhost 8000 2000
the tcp send buffer size after setting is 4000
給的是2000, 被改成4000了。
總結
以上是生活随笔為你收集整理的socket选项: SO_REUSEADDR, SO_RCVBUF, SO_SNDBUF的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。