linux網路程式設計四:socket選項: SO_REUSEADDR, SO_RCVBUF, SO_SNDBUF
最近在看《linux高效能伺服器程式設計》,在此做個日記,以激勵自己,同時分享於有需要的朋友。
1. 讀取和設定socket檔案描述符屬性:
sockfd引數指定被操作的目標socket。#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);
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些狀態也可以立即被重用。
int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizof(reuse));
4. SO_RCVBUF 和 SO_SNDBUF :TCP接收緩衝區和傳送緩衝區的大小
當然,即使我們設定了這兩項的大小時, 系統都會自動將其加倍, 並且不得小於某個最小值。
TCP接收緩衝區的最小值是 256 位元組, 而傳送緩衝區的最小值是 2048 位元組。(不同系統可能會有差異)
這麼做的目的是確保一個TCP連線擁有足夠多的空閒緩衝區來處理擁塞。
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. 程式碼
//服務端
#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;
}
執行後:
[email protected]:~/myproject/test_recv$ ./test_recv localhost 8000 50
the receive buffer size after setting is 2280
很明顯被修改過了, 我們給的50, 被改為2280。
//客戶端
#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;
}
執行後:
[email protected]:~/myproject/test_send$ ./test_send localhost 8000 2000
the tcp send buffer size after setting is 4000
給的是2000, 被改成4000了。
相關推薦
linux網路程式設計四:socket選項: SO_REUSEADDR, SO_RCVBUF, SO_SNDBUF
最近在看《linux高效能伺服器程式設計》,在此做個日記,以激勵自己,同時分享於有需要的朋友。 1. 讀取和設定socket檔案描述符屬性: #include <sys/socket.h> int getsockopt(int sockfd, int lev
linux網路程式設計二十:socket選項:SO_RCVTIMEO和SO_SNDTIMEO
SO_RCVTIMEO和SO_SNDTIMEO ,它們分別用來設定socket接收資料超時時間和傳送資料超時時間。 因此,這兩個
linux網路程式設計之用socket實現簡單客戶端和服務端的通訊(基於TCP)
一、介紹基於TCP協議通過socket實現網路程式設計常用API 1、讀者如果不是很熟悉,可以先看我之前寫的幾篇部落格,有socket,地址結構的理解,更加方便讀者理解 地址分別是: 2、socket(TCP)程式設計API簡介 1)、socket int s
linux網路程式設計之用socket實現簡單客戶端和服務端的通訊(基於UDP)
1、sendto和recvfrom函式介紹 sendto(經socket傳送資料) 相關函式 send , sendmsg,recv , recvfrom , socket 表頭檔案 #include < sys/types.h >#includ
Linux網路程式設計基礎API--socket檔案描述符API
《Linux高效能伺服器程式設計》閱讀筆記: 1. 建立socket Linux系統上”一切皆是檔案“,socket也不例外,它是可讀/可寫/可控制/可關閉的檔案描述符。要實現socket通訊,雙方都需要建立各自的socket物件。 #include
Linux網路程式設計:TCP客戶/伺服器模型及基本socket函式
TCP客戶/伺服器模型 TCP連線的分組交換 在使用socket API的時候應該清楚應用程式和TCP協議棧是如何互動的: 呼叫connect()會發出SYN段(SYN是TCP報文段頭部的一個標誌位,置為1) 阻塞的read()函式返回0就表明收到了FIN段 客戶端呼叫c
Linux網路程式設計:socket程式設計簡介、網路位元組序及相關函式
Socket(套接字) socket可以看成是使用者程序與核心網路協議棧的程式設計介面(API函式)。 socket不僅可以用於本機的程序間通訊,還可以用於網路上不同主機的程序間通訊。 IPv4套接字地址結構 IPv4套接字地址結構通常也稱為“網際套接字地址結構”,它以
Linux網路程式設計(一):一個簡單的socket程式
伺服器: /* *tcp_server.c */ #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include
linux網路程式設計之socket(十六):通過UNIX域套接字傳遞描述符和 sendmsg/recvmsg 函式
void send_fd(int sock_fd, int send_fd) { int ret; struct msghdr msg; struct cmsghdr *p_cmsg; struct iovec vec; char cmsgbuf[CMSG_SPACE(
linux網路程式設計之posix 執行緒(四):posix 條件變數與互斥鎖 示例生產者--消費者問題
#include <unistd.h>#include <sys/types.h>#include <pthread.h>#include <semaphore.h>#include <stdlib.h>#include <stdio.h>
Linux網路程式設計:使用select函式實現socket 收發資料
所謂的回射是指:客戶端A向服務端B傳送資料,服務端B接收到資料之後,再將接收到的資料傳送回客戶端B。所謂的迭代伺服器,
網路程式設計基礎【day08】:簡單socket例項(二)
本節內容 1、概述 2、socket例項 3、總結 一、概述 之前我們只是介紹了soket的概念和一些邏輯圖表,下面我們來看看,socket的客戶端和服務端到底是怎麼用的? 二、socket例項 2.1 客戶端 2.1.1 客戶端程式碼邏輯圖 2.1.2 客戶端程式碼
網路程式設計基礎【day09】:socket接收大資料(五)
本節內容 1、概述 2、socket接收大資料 3、中文字元的坑 一、概述 上篇部落格寫到了,就是說當伺服器傳送至客戶端的資料,大於客戶端設定的資料,則就會把資料服務端發過來的資料剩餘資料存在IO緩衝區中,那我們如何解決這個問題呢? 有的同學就說了: 改大客戶端接收的資料的大小=&
網路程式設計基礎【day09】:socket解決粘包問題之MD5(八)
本節內容 1、概述 2、程式碼實現 一、概述 上一篇部落格講到的用MD5來校驗還是用的之前解決粘包的方法,就是客戶端傳送一個請求,等待服務端的確認的這樣的一個笨方法。下面我們用另外一種方法:就是客戶端已經知道可接收多少資料了,既然客戶端已經知道接收多少資料了,那麼客戶端在接收資料的時候,正好接收已
網路程式設計基礎【day10】:我是一個執行緒(四)
本節內容 1、第一回 初生牛犢 2、第二回 漸入佳境 3、第三回 虎口脫險 4、第四回 江湖再見 第一回 初生牛犢 我是一個執行緒,我一出生就被編了個號:0x3704,然後被領到一個昏暗的屋子裡,在這裡我發現了很多和我一模一樣的同伴。 我身邊的同伴0x6900 待的時間比較長,他帶著滄桑的口氣對
Linux網路程式設計——原始套接字例項:MAC 頭部報文分析
通過《Linux網路程式設計——原始套接字程式設計》得知,我們可以通過原始套接字以及 recvfrom( ) 可以獲取鏈路層的資料包,那我們接收的鏈路層資料包到底長什麼樣的呢? MAC 頭部(有線區域網) 注意:CRC、PAD 在組包時可以忽略 鏈路層資料包的其中一
Linux 網路程式設計——原始套接字例項:MAC 地址掃描器
如果 A (192.168.1.1 )向 B (192.168.1.2 )傳送一個數據包,那麼需要的條件有 ip、port、使用的協議(TCP/UDP)之外還需要 MAC 地址,因為在乙太網資料包中 MAC 地址是必須要有的。那麼怎樣才能知道對方的 MAC 地址?答案是:它通
Linux 網路程式設計——原始套接字例項:傳送 UDP 資料包
乙太網(Ethernet)報文格式(MAC頭部報文格式): IP 報文格式: UDP 報文格式: 校驗和函式: /******************************************************* 功能:
《Linux網路程式設計》: 無連線和麵向連線協議的區別
網路程式設計中最基本的概念就是面向連線(connection-oriented)和無連線(connectionless)協議。儘管本質上來說,兩者之間的區別並不難理解,但對那些剛剛開始進行網路程式設計的人來說,卻是個很容易混淆的問題。這個問題與上下文有些關聯:很顯然,如果兩臺計算機要進行通訊,就必須
《Linux網路程式設計》: 網路協議入門
我們每天使用網際網路,你是否想過,它是如何實現的? 全世界幾十億臺電腦,連線在一起,兩兩通訊。北京的某一塊網絡卡送出訊號,深圳的另一塊網絡卡居然就收到了,兩者實際上根本不知道對方的物理位置,你不覺得這是很神奇的事情嗎? 為了使各種不同的計算機之間可以互聯,ARPANet指定了一套計算