溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C語言中socketpair的用法介紹

發(fā)布時間:2021-08-20 15:28:38 來源:億速云 閱讀:333 作者:chen 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“C語言中socketpair的用法介紹”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“C語言中socketpair的用法介紹”吧!

socketpair()函數(shù)的聲明:

#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int d, int type, int protocol, int sv[2]);

socketpair()函數(shù)用于創(chuàng)建一對無名的、相互連接的套接子。 
如果函數(shù)成功,則返回0,創(chuàng)建好的套接字分別是sv[0]和sv[1];否則返回-1,錯誤碼保存于errno中。

基本用法: 

  1. 這對套接字可以用于全雙工通信,每一個套接字既可以讀也可以寫。例如,可以往sv[0]中寫,從sv[1]中讀;或者從sv[1]中寫,從sv[0]中讀; 

  2. 如果往一個套接字(如sv[0])中寫入后,再從該套接字讀時會阻塞,只能在另一個套接字中(sv[1])上讀成功; 

  3. 讀、寫操作可以位于同一個進(jìn)程,也可以分別位于不同的進(jìn)程,如父子進(jìn)程。如果是父子進(jìn)程時,一般會功能分離,一個進(jìn)程用來讀,一個用來寫。因?yàn)槲募枋龈眘v[0]和sv[1]是進(jìn)程共享的,所以讀的進(jìn)程要關(guān)閉寫描述符, 反之,寫的進(jìn)程關(guān)閉讀描述符。 

舉例: 

一、讀寫操作位于同一進(jìn)程

#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <error.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
 
const char* str = "SOCKET PAIR TEST.";
 
int main(int argc, char* argv[]){
    char buf[128] = {0};
    int socket_pair[2]; 
    pid_t pid; 
 
    if(socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair) == -1 ) { 
        printf("Error, socketpair create failed, errno(%d): %s\n", errno, strerror(errno));
        return EXIT_FAILURE; 
    } 
 
    int size = write(socket_pair[0], str, strlen(str));
    //可以讀取成功;
    read(socket_pair[1], buf, size);
    printf("Read result: %s\n",buf);
    return EXIT_SUCCESS;    
}

二、讀寫操作位于不同進(jìn)程

#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <error.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
 
const char* str = "SOCKET PAIR TEST.";
 
int main(int argc, char* argv[]){
    char buf[128] = {0};
    int socket_pair[2]; 
    pid_t pid; 
 
    if(socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair) == -1 ) { 
        printf("Error, socketpair create failed, errno(%d): %s\n", errno, strerror(errno));
        return EXIT_FAILURE; 
    } 
 
    pid = fork();
    if(pid < 0) {
        printf("Error, fork failed, errno(%d): %s\n", errno, strerror(errno));
        return EXIT_FAILURE;
    } else if(pid > 0) {
        //關(guān)閉另外一個套接字
        close(socket_pair[1]);
        int size = write(socket_pair[0], str, strlen(str));
        printf("Write success, pid: %d\n", getpid());
 
    } else if(pid == 0) {
        //關(guān)閉另外一個套接字
        close(socket_pair[0]);
        read(socket_pair[1], buf, sizeof(buf));        
        printf("Read result: %s, pid: %d\n",buf, getpid());
    }
 
    for(;;) {
        sleep(1);
    }
 
    return EXIT_SUCCESS;    
}

sendmsg, recvmsg , send函數(shù)的使用

sendmsg, recvmsg , send三個函數(shù)的頭文件:

#include <sys/types.h>  
#include <sys/socket.h>

sendmsg函數(shù) 
定義函數(shù)

int sendmsg(int s, const strcut msghdr *msg, unsigned int flags);

函數(shù)說明:sendmsg()用來將數(shù)據(jù)由指定的socket傳給對方主機(jī). 
參數(shù)s:為已建立好連線的socket, 如果利用UDP協(xié)議則不需經(jīng)過連線操作. 
參數(shù)msg:指向欲連線的數(shù)據(jù)結(jié)構(gòu)內(nèi)容, 參數(shù)flags 一般默認(rèn)為0, 詳細(xì)描述請參考send(). 
返回值:成功返回發(fā)送的字節(jié)數(shù),出錯返回-1

recvmsg函數(shù) 
定義函數(shù)

int recvmsg(int s, struct msghdr *msg, unsigned int flags);

函數(shù)說明:recvmsg()用來接收遠(yuǎn)程主機(jī)經(jīng)指定的socket 傳來的數(shù)據(jù). 
參數(shù)s 為已建立好連線的socket, 如果利用UDP 協(xié)議則不需經(jīng)過連線操作. 
參數(shù)msg 指向欲連線的數(shù)據(jù)結(jié)構(gòu)內(nèi)容, 
參數(shù)flags 一般設(shè)0, 詳細(xì)描述請參考send(). 
返回值:成功則返回接收到的字符數(shù), 失敗則返回-1, 錯誤原因存于errno 中.

send函數(shù) 
定義函數(shù):int send(int s, const void * msg, int len, unsigned int falgs); 
函數(shù)說明:send()用來將數(shù)據(jù)由指定的socket 傳給對方主機(jī). 
參數(shù)s 為已建立好連接的socket. 
參數(shù)msg 指向欲連線的數(shù)據(jù)內(nèi)容. 
參數(shù)len 則為數(shù)據(jù)長度. 
參數(shù)flags 一般設(shè)0, 其他數(shù)值定義如下: 
MSG_OOB 傳送的數(shù)據(jù)以out-of-band 送出. 
MSG_DONTROUTE 取消路由表查詢 
MSG_DONTWAIT 設(shè)置為不可阻斷運(yùn)作 
MSG_NOSIGNAL 此動作不愿被SIGPIPE 信號中斷. 
返回值:成功則返回實(shí)際傳送出去的字符數(shù), 失敗返回-1. 錯誤原因存于errno.

結(jié)構(gòu)msghdr定義如下:

struct msghdr
{
    void *msg_name; //發(fā)送或接收數(shù)據(jù)的地址
    socklen_t msg_namelen; //地址長度
    strcut iovec * msg_iov; //要發(fā)送或接受數(shù)據(jù)
    size_t msg_iovlen; //容器數(shù)據(jù)長度
    void * msg_control; //附屬數(shù)據(jù)
    size_t msg_controllen; //附屬數(shù)據(jù)長度
    int msg_flags; //接收消息的標(biāo)志
};

返回值:成功則返回實(shí)際傳送出去的字符數(shù), 失敗返回-1, 錯誤原因存于errno 
錯誤代碼:

1、EBADF 參數(shù)s 非合法的socket 處理代碼.
2、EFAULT 參數(shù)中有一指針指向無法存取的內(nèi)存空間
3、ENOTSOCK 參數(shù)s 為一文件描述詞, 非socket.
4、EINTR 被信號所中斷.
5、EAGAIN 此操作會令進(jìn)程阻斷, 但參數(shù)s 的socket 為不可阻斷.
6、ENOBUFS 系統(tǒng)的緩沖內(nèi)存不足
7、ENOMEM 核心內(nèi)存不足 EINVAL 傳給系統(tǒng)調(diào)用的參數(shù)不正確.

附屬數(shù)據(jù)msg_control結(jié)構(gòu) 
控制信息頭部本身由下面的C結(jié)構(gòu)定義:

struct cmsghdr {
    socklen_t cmsg_len;
    int       cmsg_level;
    int       cmsg_type;
/* u_char     cmsg_data[]; */
};

其成員描述如下:

成員             描述
cmsg_len        附屬數(shù)據(jù)的字節(jié)計(jì)數(shù),這包含結(jié)構(gòu)頭的尺寸。這個值是由CMSG_LEN()宏計(jì)算的。
cmsg_level      這個值表明了原始的協(xié)議級別(例如,SOL_SOCKET)。
cmsg_type       這個值表明了控制信息類型(例如,SCM_RIGHTS)。
cmsg_data       這個成員并不實(shí)際存在,用來指明實(shí)際的額外附屬數(shù)據(jù)所在的位置。

用sendmsg來傳遞數(shù)據(jù)程序?qū)嵗?/p>

/*sendmsg.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
 
int main(int argc,char *argv[])
{
    int ret;     /* 返回值 */
    int sock[2];    /* 套接字對 */
    struct msghdr msg;
    struct iovec iov[1];
    char send_buf[100] = "it is a test";
    struct msghdr msgr;
    struct iovec iovr[1];
    char recv_buf[100];
 
    /* 創(chuàng)建套接字對 */
    ret = socketpair(AF_LOCAL,SOCK_STREAM,0,sock);
    if(ret == -1){
        printf("socketpair err\n");
        return 1;   
    }
 
    /* sock[1]發(fā)送數(shù)據(jù)到本地主機(jī)  */
    bzero(&msg, sizeof(msg));
    msg.msg_name = NULL;        /* void*類型 NULL本地地址*/
    msg.msg_namelen = 0;
    iov[0].iov_base = send_buf;
    iov[0].iov_len = sizeof(send_buf);
    msg.msg_iov = iov;//要發(fā)送或接受數(shù)據(jù)設(shè)為iov
    msg.msg_iovlen = 1;//1個元素
 
    printf("開始發(fā)送數(shù)據(jù):\n");
    printf("發(fā)送的數(shù)據(jù)為: %s\n", send_buf);
    ret = sendmsg(sock[1], &msg, 0 );
    if(ret == -1 ){
        printf("sendmsg err\n");
        return -1;
    }
    printf("發(fā)送成功!\n");
 
    /* 通過sock[0]接收發(fā)送過來的數(shù)據(jù) */
    bzero(&msg, sizeof(msg));
    msgr.msg_name = NULL;   
    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;
    ret = recvmsg(sock[0], &msgr, 0);
    if(ret == -1 ){
        printf("recvmsg err\n");
        return -1;
    }
    printf("接收成功!\n");
    printf("收到數(shù)據(jù)為: %s\n", recv_buf);
 
    /* 關(guān)閉sockets */
    close(sock[0]);
    close(sock[1]);
 
    return 0;
}

執(zhí)行程序結(jié)果:

yu@ubuntu:~/Linux/217/pro_pool/socketpair$ gcc -o sendmsg sendmsg.c

yu@ubuntu:~/Linux/217/pro_pool/socketpair$ ./sendmsg
開始發(fā)送數(shù)據(jù):
發(fā)送的數(shù)據(jù)為: it is a test
發(fā)送成功!
接收成功! 

接到數(shù)據(jù)為:it is a test

程序分析:由套接字sock[1]發(fā)數(shù)據(jù)到本地主機(jī),由套接字sock[0]接收發(fā)送過來的數(shù)據(jù)。

到此,相信大家對“C語言中socketpair的用法介紹”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI