SOCKET之 socketpair的使用

2021-09-30 15:17:22 字數 4466 閱讀 4868

socketpair函式概要如下:

#include

#include

int socketpair(int domain, int type, int protocol, int sv[2]);

sys/types.**件需要用來定義一些c巨集常量。sys/socket.**件必須包含進來定義socketpair函式原型。

socketpair函式需要四個引數。他們是:

套介面的域

套介面型別

使用的協議

指向儲存檔案描述符的指標

型別引數宣告了我們希望建立哪種型別的套介面。socketpair函式的選擇如下:

sock_stream

sock_dgram

對於socketpair函式,protocol引數必須提供為0。

引數sv[2]是接收代表兩個套介面的整數陣列。每乙個檔案描述符代表乙個套介面,並且與另乙個並沒有區別。

如果函式成功,將會返回0值。否則將會返回-1表明建立失敗,並且errno來表明特定的錯誤號。

關於流程。socketpair()函式建立出兩個程序,fork()之後這兩個程序都會執行主程式中的**,這個一定要注意!尤其是bind的時候,如果bind兩次的話,那就會出錯了。一般會在子程序裡呼叫乙個帶死迴圈的函式,這樣就好了。(這個情況的例子會在綜合運用中講解)

一下給出個簡單的例子。

// 建立socket對

#include

#include

#include

#include

int main ()

if ( fork() )

}else }}

在給出乙個用sendmsg來傳遞資料的例子

/*****************************************

** listing 1.2

** example performing i/o on s socket pair:

** ******************************************/

#include

#include

#include

#include

#include

#include

#include

int main(int argc,char **ar**)

/** sendmsg s[1]:

*/bzero(&msg, sizeof(msg));

msg.msg_name = null; /* attention this is a pointer to void* type */

msg.msg_namelen = 0;

iov[0].iov_base = send_buf;

iov[0].iov_len = sizeof(send_buf);

msg.msg_iov = iov;

msg.msg_iovlen = 1;

printf("sendmsg begin.\n");

z = sendmsg( s[1], &msg, 0 );

if(z == -1 )

printf("sendmsg success!\n");

/** read from socket s[0]:

*/bzero(&msg, sizeof(msg));

msgr.msg_name = null; /* attention this is a pointer to void* type */

msgr.msg_namelen = 0;

iovr[0].iov_base = &recv_buf;

iovr[0].iov_len = sizeof(recv_buf);

msgr.msg_iov = iovr;

msgr.msg_iovlen = 1;

z = recvmsg( s[0], &msgr, 0);

if(z == -1 )

printf("recvmsg success!\n");

printf("recvmsg : %s\n", recv_buf);

/** close the sockets:

*/close(s[0]);

close(s[1]);

puts("done");

return 0;}

ttp:

我們知道父程序在子程序被fork出來之前開啟的檔案描述符是能被子程序繼承下來的,但是一旦子程序已經建立後,父程序開啟的檔案描述符要怎樣才能傳遞給子程序呢?unix提供相應的技術來滿足這一需求,這就是同一臺主機上程序間的檔案描述符傳遞,很美妙而且強大的技術。

想象一下我們試圖實現乙個伺服器,接收多個客戶端的連線,我們欲採用多個子程序併發的形式來處理多客戶端的同時連線,這時候我們可能有兩種想法:

1、客戶端每建立一條連線,我們fork出乙個子程序負責處理該連線;

2、預先建立乙個程序池,客戶端每建立一條鏈結,伺服器就從該池中選出乙個空閒(idle)子程序來處理該連線。

後者顯然更高效,因為減少了子程序建立的效能損耗,反應的及時性大大增強。這裡恰恰就出現了我們前面提到的問題,所有子程序都是在伺服器listen到一條連線以前就已經fork出來了,也就是說新的連線描述符子程序是不知道的,需要父程序傳遞給它,它接收到相應的連線描述符後,才能與相應的客戶端進行通訊處理。這裡我們就可以使用'傳遞檔案描述符'的方式來實現。

在'unix網路程式設計第1卷'的14.7小節中對這種技術有詳細的闡述,實際上這種技術就是利用sendmsg和recvmsg在一定的unix域套介面(或者是某種管道)上傳送和接收一種特殊的訊息,這種訊息可以承載'檔案描述符'罷了,當然作業系統核心對這種訊息作了特殊的處理。在具體一點兒'檔案描述符'是作為輔助資料(ancillary data)通過msghdr結構中的成員msg_control(老版本中稱為msg_accrights)傳送和接收的。值得一提的是傳送程序在將'檔案描述符'傳送出去後,即使立即關閉該檔案描述符,該檔案描述符對應的檔案裝置也沒有被真正的關閉,其引用計數仍然大於一,直到接收程序成功接收後,再關閉該檔案描述符,如果這時檔案裝置的引用計數為0,那麼才真正關閉該檔案裝置。

ok,下面是乙個簡單的檔案描述符傳遞的例子,該例子實現這樣乙個功能:即子程序負責在父程序傳遞給它的檔案描述符對應的檔案尾加上特定的'logo'字串。例子環境為solaris 9 + gcc 3.2

/* test_fdpass.c */

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include /* for socketpair */

#define my_logo "-- tony bai"

static int send_fd(int fd, int fd_to_send)

else

msg.msg_name = null;

msg.msg_namelen = 0;

iov[0].iov_base = buf;

iov[0].iov_len = 1;

msg.msg_iov = iov;

msg.msg_iovlen = 1;

if(sendmsg(fd, &msg, 0) < 0)

return 0;

}static int recv_fd(int fd, int *fd_to_recv)

if(msg.msg_accrightslen != sizeof(int))

return 0;

}intx_sock_set_block(int sock, int on)

else

if (rv)

return 0;

}int main()

pid = fork();

if (pid == 0)

rv = recv_fd(sockpair[0], &fd);

if (rv < 0)

if (fd < 0)

exit(0);

}/* in parent */

for ( ; ; )

break;

}rv = send_fd(sockpair[1], fd);

if (rv != 0)

close(fd);

}wait(null);

return 0;

}編譯:gcc -o test_fdpass -lsocket -lnsl test_fdpass.c

執行:test_fdpass(事先在同一目錄下建立乙個檔案kk.log)

你可以發現kk.log內容的末尾已經加上了我的獨特logo '-- tony bai'。^_^

關於檔案描述符傳遞的更多細節, w. richard stevens的'unix網路程式設計第1卷'和'unix環境高階程式設計'兩本書中都有詳細說明,參讀即可。

C 之Socket程式設計

using system using system.collections.generic using system.linq using system.text encoding類 using system.threading.tasks using system.net.sockets usin...

socket之核心操作

簡單記錄下socket之核心操作 之前面試有被問到socket傳送訊息在作業系統底層是怎麼弄的 首先 客戶端和服務端建立好socket套接字的時候,雙方都可以通過套接字進行訊息的收發,因為socket中維護了兩個佇列,傳送佇列和接受佇列。傳送時,資料儲存在使用者的記憶體中,使用者呼叫send和wri...

UDP之Socket程式設計

建立服務端socket物件 datagramsocket datagramsocket server newdatagramsocket 12331 建立接受資料報的容器 byte bytes newbyte 1024 datagrampacket packet newdatagrampacket ...