Linux下getsockopt/setsockopt 函數說明__安卓

來源:互聯網
上載者:User
Linux下getsockopt/setsockopt 函數說明

【 getsockopt/setsockopt系統調用】  
   
功能描述:
擷取或者設定與某個通訊端關聯的選 項。選項可能存在於多層協議中,它們總會出現在最上面的通訊端層。當操作通訊端選項時,選項位於的層和選項的名稱必須給出。為了操作通訊端層的選項,應該 將層的值指定為SOL_SOCKET。為了操作其它層的選項,控制選項的合適協議號必須給出。例如,為了表示一個選項由TCP協議解析,層應該設定為協議 號TCP。


用法:
#include <sys/types.h>
#include <sys/socket.h>

int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

參數:  
sock:將要被設定或者擷取選項的通訊端。
level:選項所在的協議層。
optname:需要訪問的選項名。
optval:對於getsockopt(),指向返回選項值的緩衝。對於setsockopt(),指向包含新選項值的緩衝。
optlen:對於getsockopt(),作為入口參數時,選項值的最大長度。作為出口參數時,選項值的實際長度。對於setsockopt(),現選項的長度。

   
返回說明:  
成功執行時,返回0。失敗返回-1,errno被設為以下的某個值  
EBADF:sock不是有效檔案描述詞
EFAULT:optval指向的記憶體並非有效進程空間
EINVAL:在調用setsockopt()時,optlen無效
ENOPROTOOPT:指定的協議層不能識別選項
ENOTSOCK:sock描述的不是通訊端

首Crowdsourced Security Testing道setsockopt()函數的KEEPALIVE屬性是周期地測試連接是否仍存活,
我上網查了很多資料還是不知道如何使用,
最後硬著頭皮自己寫了一個伺服器端和一個用戶端的通訊端串連
分別設定了兩端的KEEPALIVE屬性為開啟
伺服器端:
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<error.h>
#include<string.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/wait.h>
#include<arpa/inet.h>
#include<unistd.h>

#define SERVPORT 6000 //設定伺服器服務連接埠為6000
#define MAX_LISTEN_SOCK_NUM 20 //設定可監聽通訊端的最大個數為20
int main()
{
//sockfd為本地監聽通訊端標識符,client_fd為用戶端通訊端標識符
int sockfd,client_fd;
struct sockaddr_in my_addr;
struct sockaddr_in client_addr;

//建立本地監聽通訊端
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
perror("通訊端建立失敗!/n");
exit(1);
}

//設定通訊端的屬性使它能夠在電腦重啟的時候可以再次使用通訊端的連接埠和IP
int err,sock_reuse=1;
err=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(char *)&sock_reuse,sizeof(sock_reuse));
if(err!=0){
printf("通訊端可重用設定失敗!/n");
exit(1);
}
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr=INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
//綁定通訊端
if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1){
perror("綁定失敗!/n");
exit(1);
}
//設定監聽
if((listen(sockfd,MAX_LISTEN_SOCK_NUM))==-1){
perror("設定監聽失敗!/n");
exit(1);
}
printf("通訊端進入監聽狀態,等待請求串連:/n");

//int time_to_quit=1;
//while(time_to_quit){ //可以通過設定time_to_quit來主動關閉伺服器端
while(1){

//有串連請求時進行串連
socklen_t sin_size=sizeof(struct sockaddr_in);
if((client_fd=accept(sockfd,(struct sockaddr *)&client_addr,&sin_size))==-1){
perror("接受串連失敗!/n");
continue;
}

int opt;
socklen_t len=sizeof(int);
if((getsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,(char*)&opt,&len))==0){
printf("SO_KEEPALIVE Value: %d/n", opt);
}
printf("接到一個來自%s的串連/n",inet_ntoa(client_addr.sin_addr));
//建立子進程來處理已串連的用戶端通訊端

if(send(client_fd,"您好,您已經串連成功!/n",50,0)==-1){
perror("發送通知資訊失敗!/n");
exit(0);
}

}
close(client_fd);

return 0;
}
用戶端:
#include<stdio.h>
#include<stdlib.h>
#include<error.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<unistd.h>
#include<arpa/inet.h>
#define MAXDATASIZE 100 /*每次最大資料轉送量*/
int main()
{
int sockfd,nbytes,serv_port;
char buf_serv_ip[16],buf[26];
struct sockaddr_in serv_addr;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
perror("建立通訊端失敗!/n");
exit(1);
}
//建立通訊端成功後設定其可重用的屬性
int KeepAlive=1;
socklen_t KPlen=sizeof(int);
if(setsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,(char *)&KeepAlive,KPlen)!=0){
perror("設定周期測試連接是否仍存活失敗!/n");
exit(1);
}
printf("請輸入要串連主機的IP地址:/n");
scanf("%s",buf_serv_ip);
printf("請輸入要串連主機的連接埠號碼:/n");
scanf("%d",&serv_port);
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=inet_addr(buf_serv_ip);
serv_addr.sin_port=htons(serv_port);
bzero(&(serv_addr.sin_zero),8);
if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))==-1){
perror("串連伺服器失敗!/n");
exit(1);
}
printf("串連伺服器成功!/n");
//在此處可以先接受判斷將要接受資料的長度再建立數組
if((nbytes=recv(sockfd,buf,26,0))==-1){
perror("接受資料失敗!/n");
exit(1);
}
buf[nbytes]='/0';
printf("接受的資料為:%s/n",buf);
close(sockfd);
return 0;
}
分別在兩個終端運(在同一個主機上)行:先啟動伺服器端;再啟動用戶端,向伺服器端請求串連,串連成功後,用戶端通訊端關閉,伺服器端通訊端始終開啟,等待兩個小時多也沒有反應,

肯請高手指點:
(1)這樣做能達到預期報告串連是否仍存在的效果嗎,
(2)不能的話應該如何做,
(3)還有getsockopt()的相關功能又是什麼哪。在上面的程式中沒有用到該函數
(4)看了unix網路編程上的一點關於該問題的解釋還是不明白,因為她提到要兩個小時才回應,但等了撒小時也沒有反應,她還說可以縮短時間,我卻不知道如何縮短 getsockopt和setsockopt 

int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen)
int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t *optlen)

level指定控制通訊端的層次.可以取三種值:
1)SOL_SOCKET:通用通訊端選項.
2)IPPROTO_IP:IP選項.
3)IPPROTO_TCP:TCP選項. 
optname指定控制的方式(選項的名稱),我們下面詳細解釋 

optval獲得或者是設定通訊端選項.根據選項名稱的資料類型進行轉換 


選項名稱        說明                  資料類型
========================================================================
            SOL_SOCKET
------------------------------------------------------------------------
SO_BROADCAST      允許發送廣播資料            int
SO_DEBUG        允許調試                int
SO_DONTROUTE      不尋找路由               int
SO_ERROR        獲得通訊端錯誤             int
SO_KEEPALIVE      保持串連                int
SO_LINGER        延遲關閉串連              struct linger
SO_OOBINLINE      帶外資料放入正常資料流         int
SO_RCVBUF        接收緩衝區大小             int
SO_SNDBUF        發送緩衝區大小             int
SO_RCVLOWAT       接收緩衝區下限             int
SO_SNDLOWAT       發送緩衝區下限             int
SO_RCVTIMEO       接收逾時                struct timeval
SO_SNDTIMEO       發送逾時                struct timeval
SO_REUSERADDR      允許重用本地地址和連接埠         int
SO_TYPE         獲得通訊端類型             int
SO_BSDCOMPAT      與BSD系統相容              int
========================================================================
            IPPROTO_IP
------------------------------------------------------------------------
IP_HDRINCL       在資料包中包含IP首部          int
IP_OPTINOS       IP首部選項               int
IP_TOS         服務類型
IP_TTL         存留時間                int
========================================================================
            IPPRO_TCP
------------------------------------------------------------------------
TCP_MAXSEG       TCP最大資料區段的大小           int
TCP_NODELAY       不使用Nagle演算法             int
========================================================================

返回說明:  
成功執行時,返回0。失敗返回-1,errno被設為以下的某個值  
EBADF:sock不是有效檔案描述詞
EFAULT:optval指向的記憶體並非有效進程空間
EINVAL:在調用setsockopt()時,optlen無效
ENOPROTOOPT:指定的協議層不能識別選項
ENOTSOCK:sock描述的不是通訊端

SO_RCVBUF和SO_SNDBUF每個套介面都有一個發送緩衝區和一個接收緩衝區,使用這兩個套介面選項可以改變預設緩衝區大小。

// 接收緩衝區
int nRecvBuf=32*1024;         //設定為32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

//發送緩衝區
int nSendBuf=32*1024;//設定為32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

注意:

當設定TCP套介面接收緩衝區的大小時,函數調用順序是很重要的,因為TCP的視窗規模選項是在建立串連時用SYN與對方互換得到的。對於客戶,SO_RCVBUF選項必須在connect之前設定;對於伺服器,SO_RCVBUF選項必須在listen前設定。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.