獲取和設置影響套接口選項的函數:
getsockopt :獲取套接口選項
setsockopt: 獲取套接口選項
fcntl: 設置套接口為非阻塞I/O型信號驅動I/O型等
oictl
套接口選項
SO-KEEPALIVE
SO-LINGER
SE-RCVBUF 和 SO-SNDBUF
SO-RCVWAT和 SO-SNDLOWAT
SO-RCVTIMEO和 SO-SNDTIMEO
SO-REUSEADDR和 SO-REUSPORT
IP-TTL
TCP-KEEPALIVE
getsockopt 和 setsockopt
獲得套接口選項:
int getsockopt ( int sockfd, int level, int optname,
void * optval, socklen_t *opteln )
設置套接口選項:
int setsockopt ( int sockfd, int level, int optname,
const void * optval, socklen_t *opteln )
sockfd(套接字): 指向一個打開的套接口描述字
level:(級別): 指定選項代碼的類型。
SOL_SOCKET: 基本套接口
IPPROTO_IP: IPv4套接口
IPPROTO_IPV6: IPv6套接口
IPPROTO_TCP: TCP套接口
optname(選項名): 選項名稱
optval(選項值): 是一個指向變量的指針
類型:整形,套接口結構, 其他結構類型:linger{}, timeval{ }
optlen(選項長度) :optval 的大小
返回值:標志打開或關閉某個特征的二進制選項
檢查套接口選項的程序
輸出套接口的選項:
定義感興趣的套接口選項
調用getsockopt
輸出套接口選項
定義聯合:不同的套接口選項有不同類型
union val { //套接口選項可能有的5個類型分別作為一個成員:
int i_val;
long l_val;
char c_val[10];
struct linger linger_val;
struct timeval timeval_val; //struct {int S; int uS}
} val;
//函數原型(prototype),這些函數用輸出套接口選項的值
static char *sock_str_flag(union val *, int); //靜態函數,只可在本文件中被調用
static char *sock_str_int(union val *, int);
static char *sock_str_linger(union val *, int);
static char *sock_str_timeval(union val *, int);
//定義結構sock_opts, 其中包含了獲得或輸出套接口選項的所有信息
struct sock_opts {
char *opt_str; //字符名稱
int opt_level; //級別
int opt_name; //名稱
char *(*opt_val_str)(union val *, int); //函數指針,用輸出,
}
//定義結構數組並初始化
struct sock_opts sock_opts[ ] = { //全局變量數組才可以初始化
"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, sock_str_flag,
"SO_DEBUG", SOL_SOCKET, SO_DEBUG, sock_str_flag,
#ifdef SO_REUSEPORT //編譯時用的宏定義
"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, sock_str_flag,
#else //沒有這個選項
"SO_REUSEPORT", 0, 0, NULL, //NULL表示沒有定義
#endif
"SO_TYPE", SOL_SOCKET, SO_TYPE, sock_str_int,
"IP_TTL", IPPROTO_IP, IP_TTL, sock_str_int,
"TCP_MAXSEG", IPPROTO_TCP,TCP_MAXSEG, sock_str_int,
NULL, { /*結束標志 */} 0, 0, NULL
};
源程序:
int main(int argc, char **argv)
{
int fd, len;
struct sock_opts *ptr; //結構類型
fd = Socket(AF_INET, SOCK_STREAM, 0); //獲得套接字
for (ptr = sock_opts; ptr->opt_str != NULL; ptr++) { //從第一個選項到最一個
printf(“%s: ”, ptr->opt_str); //輸出字符名
if (ptr->opt_val_str == NULL) //沒有定義的情況
printf("(undefined)\n");
else {
len = sizeof(val);
//獲得套接口選項
if (getsockopt(fd, ptr->opt_level, ptr->opt_name, val, len) == -1) {
//返回值為1,函數調用失敗
err_ret("getsockopt error");}
//輸出選項的缺省值
else printf("default = %s\n", (*ptr->opt_val_str)(&val, len));
}
} //End of for loop
exit(0);
}
static char strres[128]; //靜態變量,在函數調用保留原值
static char * sock_str_flag(union val *ptr, int len)
{
if (len != sizeof(int)) //長度不相符
snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
else
//轉換字符串
snprintf(strres, sizeof(strres),"%s", (ptr->i_val == 0) ? "off" : "on");
return(strres);
}
基本套接口選項
SO_KEEPALIVE
檢測對方主機是否崩潰,避免(服務器)永遠阻塞TCP連接的輸入。
設置該選項,如果2小時內在此套接口的任一方向都沒有數據交換,TCP就自動給對方
發一個保持存活探測分節(keepalive probe)。這是一個對方必須響應的TCP分節.它會導
致以下三種情況:
對方接收一切正常:以期望的ACK響應。2小時,TCP將發出另一個探測分節。
對方已崩潰且已重新啟動:以RST響應。套接口的待處理錯誤被置為ECONNRESET,套接
口本身則被關閉。
對方無任何響應:源自berkeley的TCP發送另外8個探測分節,相隔75秒一個,試圖得到
一個響應。在發出第一個探測分節11分鐘15秒若仍無響應就放棄。套接口的待處理錯
誤被置為ETIMEOUT,套接口本身則被關閉。如ICMP錯誤是“host unreachable(主機不
可達)”,說明對方主機並沒有崩潰,但是不可達,這種情況下待處理錯誤被置為
EHOSTUNREACH。
SO_RCVBUF和SO_SNDBUF
每個套接口都有一個發送緩沖區和一個接收緩沖區。
接收緩沖區被TCP和UDP用來將接收到的數據一直保存到由應用進程來讀。
TCP:TCP通告另一端的窗口大小。
TCP套接口接收緩沖區不可能溢出,因為對方不允許發出超過所通告窗口大小的數據。
這就是TCP的流量控制,如果對方無視窗口大小而發出了超過宙口大小的數據,則接
收方TCP將丟棄它。
UDP:當接收到的數據報裝不進套接口接收緩沖區時,此數據報就被丟棄。UDP是沒有
流量控制的;快的發送者可以很容易地就淹沒慢的接收者,導致接收方的UDP丟棄數據報。
SO_LINGER
指定函數CLOSE對面相連接的協議如何操作當由數據殘留在套接口發送緩沖區時的處理
LINGER結構
struct linger {
int l_onoff; // 0=off, nonzero=on
int l_linger; //linger time in seconds
};
SO_RCVLOWAT 和SO_SNDLOWAT
每個套接口都有一個接收低潮限度和一個發送低潮限度。它們是函數selectt使用的,
接收低潮限度是讓select返回“可讀”而在套接口接收緩沖區中必須有的數據總量。
對一個TCP或UDP套接口,此值缺省為1。發送低潮限度是讓select返回“可寫”
而在套接口發送緩沖區中必須有的可用空間。對TCP套接口,此值常缺省為2048。
對UDP使用低潮限度, 由其發送緩沖區中可用空間的字節數是從不變化的,只要
UDP套接口發送緩沖區大小大套接口的低潮限度,這樣的UDP套接口就總是可寫的。
UDP沒有發送緩沖區,只有發送緩沖區的大小。
TCP 套接口選項
TCP_KEEPALIVE
指定TCP開始發送保持存活探測分節前以秒為單位的連接空閑時間。缺省值至少必須
為7200秒,即2小時。此選項僅在SO_KEPALIVEE套接口選項打開時才有效。
TCP_MAXSEG
獲取或設置TCP連接的最大分節大小(MSS)。返回值是我們的TCP發送給另一端的最大
數據量,它常常就是由另一端用SYN分節通告的MSS,除非我們的TCP選擇使用一個比
對方通告的MSS小些的值。如果此值在套接口連接之前取得,則返回值為未從另﹒端
收到Mss選項的情況下所用的缺省值。小此返回值的信可能真正用在連接上,因為譬
如說使用時間戳選項的話,它在每個分節上佔用12字節的TCP選項容量。我們的TcP將
發送的每個分節的最大數據量也可在連接存活期內改變,但前提是TCP要支持路徑MTU
發現功能。如果到對方的路徑改變了,此值可上下調整。
例程序:
//獲得發送緩沖區大小和MSS大小,設置發送緩沖區大小
//獲得發送緩沖區大小和MSS大小
#include "unp.h"
#include /* for TCP_MAXSEG */
int main(int argc, char **argv)
{ int sockfd, rcvbuf, mss;
socklen_t len;
struct sockaddr_in servaddr;
if (argc != 2) err_quit("usage: rcvbuf ");
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
len = sizeof(rcvbuf);
Getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, rcvbuf, len);
len = sizeof(mss);
Getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len);
printf("defaults: SO_RCVBUF = %d, MSS = %d\n", rcvbuf, mss);
bzero(servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13); /* daytime server */
Inet_pton(AF_INET, argv[1], servaddr.sin_addr);
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
len = sizeof(rcvbuf);
Getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &len);
len = sizeof(mss);
Getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len);
printf("after connect: SO_RCVBUF = %d, MSS = %d\n", rcvbuf, mss);
exit(0);
}
//設置發送緩沖區大小
#include "unp.h"
#include /* for TCP_MAXSEG value */
int
main(int argc, char **argv)
{
int sockfd, mss, sendbuff;
socklen_t optlen;
float kk;
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
/* Fetch and print the TCP maximum segment size. */
optlen = sizeof(mss);
sendbuff =2048;
Setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, sendbuff, sizeof(sendbuff));
optlen = sizeof(sendbuff);
Getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, sendbuff, &optlen);
printf("After send buffer size = %d\n", sendbuff);
exit(0);
}
(http://www.fanqiang.com)
進入【