服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言 socketpair用法案例讲解

C语言 socketpair用法案例讲解

2021-12-20 15:16雪过无痕_ C/C++

这篇文章主要介绍了C语言 socketpair用法案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

socketpair()函数的声明:

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

socketpair()函数用于创建一对无名的、相互连接的套接子。 
如果函数成功,则返回0,创建好的套接字分别是sv[0]和sv[1];否则返回-1,错误码保存于errno中。

基本用法: 

  1. 这对套接字可以用于全双工通信,每一个套接字既可以读也可以写。例如,可以往sv[0]中写,从sv[1]中读;或者从sv[1]中写,从sv[0]中读; 
  2. 如果往一个套接字(如sv[0])中写入后,再从该套接字读时会阻塞,只能在另一个套接字中(sv[1])上读成功; 
  3. 读、写操作可以位于同一个进程,也可以分别位于不同的进程,如父子进程。如果是父子进程时,一般会功能分离,一个进程用来读,一个用来写。因为文件描述副sv[0]和sv[1]是进程共享的,所以读的进程要关闭写描述符, 反之,写的进程关闭读描述符。 

举例: 

一、读写操作位于同一进程

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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;   
}

二、读写操作位于不同进程

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#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) {
        //关闭另外一个套接字
        close(socket_pair[1]);
        int size = write(socket_pair[0], str, strlen(str));
        printf("Write success, pid: %d\n", getpid());
 
    } else if(pid == 0) {
        //关闭另外一个套接字
        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函数的使用

sendmsg, recvmsg , send三个函数的头文件:

?
1
2
#include <sys/types.h> 
#include <sys/socket.h>

sendmsg函数 
定义函数

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

函数说明:sendmsg()用来将数据由指定的socket传给对方主机. 
参数s:为已建立好连线的socket, 如果利用UDP协议则不需经过连线操作. 
参数msg:指向欲连线的数据结构内容, 参数flags 一般默认为0, 详细描述请参考send(). 
返回值:成功返回发送的字节数,出错返回-1

recvmsg函数 
定义函数

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

函数说明:recvmsg()用来接收远程主机经指定的socket 传来的数据. 
参数s 为已建立好连线的socket, 如果利用UDP 协议则不需经过连线操作. 
参数msg 指向欲连线的数据结构内容, 
参数flags 一般设0, 详细描述请参考send(). 
返回值:成功则返回接收到的字符数, 失败则返回-1, 错误原因存于errno 中.

send函数 
定义函数:int send(int s, const void * msg, int len, unsigned int falgs); 
函数说明:send()用来将数据由指定的socket 传给对方主机. 
参数s 为已建立好连接的socket. 
参数msg 指向欲连线的数据内容. 
参数len 则为数据长度. 
参数flags 一般设0, 其他数值定义如下: 
MSG_OOB 传送的数据以out-of-band 送出. 
MSG_DONTROUTE 取消路由表查询 
MSG_DONTWAIT 设置为不可阻断运作 
MSG_NOSIGNAL 此动作不愿被SIGPIPE 信号中断. 
返回值:成功则返回实际传送出去的字符数, 失败返回-1. 错误原因存于errno.

结构msghdr定义如下:

?
1
2
3
4
5
6
7
8
9
10
struct msghdr
{
    void *msg_name; //发送或接收数据的地址
    socklen_t msg_namelen; //地址长度
    strcut iovec * msg_iov; //要发送或接受数据
    size_t msg_iovlen; //容器数据长度
    void * msg_control; //附属数据
    size_t msg_controllen; //附属数据长度
    int msg_flags; //接收消息的标志
};

返回值:成功则返回实际传送出去的字符数, 失败返回-1, 错误原因存于errno 
错误代码:

?
1
2
3
4
5
6
7
1、EBADF 参数s 非合法的socket 处理代码.
2、EFAULT 参数中有一指针指向无法存取的内存空间
3、ENOTSOCK 参数s 为一文件描述词, 非socket.
4、EINTR 被信号所中断.
5、EAGAIN 此操作会令进程阻断, 但参数s 的socket 为不可阻断.
6、ENOBUFS 系统的缓冲内存不足
7、ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确.

附属数据msg_control结构 
控制信息头部本身由下面的C结构定义:

?
1
2
3
4
5
6
struct cmsghdr {
    socklen_t cmsg_len;
    int       cmsg_level;
    int       cmsg_type;
/* u_char     cmsg_data[]; */
};

其成员描述如下:

?
1
2
3
4
5
成员             描述
cmsg_len        附属数据的字节计数,这包含结构头的尺寸。这个值是由CMSG_LEN()宏计算的。
cmsg_level      这个值表明了原始的协议级别(例如,SOL_SOCKET)。
cmsg_type       这个值表明了控制信息类型(例如,SCM_RIGHTS)。
cmsg_data       这个成员并不实际存在,用来指明实际的额外附属数据所在的位置。

用sendmsg来传递数据程序实例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*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];
 
    /* 创建套接字对 */
    ret = socketpair(AF_LOCAL,SOCK_STREAM,0,sock);
    if(ret == -1){
        printf("socketpair err\n");
        return 1;  
    }
 
    /* sock[1]发送数据到本地主机  */
    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;//要发送或接受数据设为iov
    msg.msg_iovlen = 1;//1个元素
 
    printf("开始发送数据:\n");
    printf("发送的数据为: %s\n", send_buf);
    ret = sendmsg(sock[1], &msg, 0 );
    if(ret == -1 ){
        printf("sendmsg err\n");
        return -1;
    }
    printf("发送成功!\n");
 
    /* 通过sock[0]接收发送过来的数据 */
    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("收到数据为: %s\n", recv_buf);
 
    /* 关闭sockets */
    close(sock[0]);
    close(sock[1]);
 
    return 0;
}

执行程序结果:

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

yu@ubuntu:~/Linux/217/pro_pool/socketpair$ ./sendmsg
开始发送数据:
发送的数据为: it is a test
发送成功!
接收成功! 

接到数据为:it is a test

程序分析:由套接字sock[1]发数据到本地主机,由套接字sock[0]接收发送过来的数据。

到此这篇关于C语言 socketpair用法案例讲解的文章就介绍到这了,更多相关C语言 socketpair用法内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/weixin_40039738/article/details/81095013

延伸 · 阅读

精彩推荐
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12