socketpair系统调用

socketpair源自BSD,可以实现在同一个文件描述符中进行读写。
该系统调用能创建一对已连接的UNIX族socket。
在Linux中,完全可以把这一对socket当成pipe返回的文件描述符一样使用,唯一的区别就是这一对文件描述符中的任何一个都可读和可写。

函数原型如下

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

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

socketpair()函数建立一对匿名的已经连接的套接字,其特性由协议族domain、类型type、协议protocol决定,建立的两个套接字描述符会放在sv[0]和sv[1]中。

参数说明

  • domain,表示协议族,只能为AF_LOCAL或者AF_UNIX。
  • type,表示协议,可以是SOCK_STREAM或者SOCK_DGRAM。用SOCK_STREAM建立的套接字对是管道流,与一般的管道相区别的是,套接字对建立的通道是双向的,即每一端都可以进行读写。
  • protocol,表示类型,只能为0。
  • sv[2]是接收代表两个套接口的整数数组。每一个文件描述符代表一个套接口,并且与另一个并没有区别。

函数返回值

如果函数成功,将会返回0值。否则将会返回-1表明创建失败,并且errno来表明特定的错误号。

简单示例

以下给出个简单的例子,通过socketpair实现父子间进程通信:

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

int main ()
{
    int fd[2];
    int r = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
    if (r < 0){
        perror( "socketpair()" );
        exit(1);
    }

    if (fork()){ /* 父进程 */
        int val = 0;
        close(fd[1]);
        while (1){
            sleep(1);
            ++val;
            printf("发送数据: %d\n", val);
            write(fd[0], &val, sizeof(val));
            read(fd[0], &val, sizeof(val));
            printf("接收数据: %d\n", val);
        }
    }else{  /*子进程*/
        int val;
        close(fd[0]);
        while(1){
            read(fd[1], &val, sizeof(val));
            ++val;
            write(fd[1], &val, sizeof(val));
        }
    }
}

执行结果

yu@ubuntu:~/Linux/217/pro_pool/socketpair$ vi socketpair1.c
yu@ubuntu:~/Linux/217/pro_pool/socketpair$ gcc -o socketpair1 socketpair1.c
yu@ubuntu:~/Linux/217/pro_pool/socketpair$ ./socketpair1
发送数据: 1
接收数据: 2
发送数据: 3
接收数据: 4
发送数据: 5
接收数据: 6
...

一开始由socketpair创建一个套接字对,父进程关闭fd[1],子进程关闭fd[0],父进程sleep(1)让子进程先执行,子进程read(fd[1], &val, sizeof(val))阻塞,然后父进程write(fd[0]..)发送数据,子进程接收数据处理后再发送给父进程数据write(fd[1]..),父进程读取数据,打印输出。(注意:socketpair产生的套接字对实现全双工通信)

标签: socket 系统调用 网络编程

精彩评论
  1. 由于其双向传输是基于文件描述符的,所以只能应用于单个进程或者有派生关系的父子进程或者多线程中,而在没有派生关系的多进程中则无法很方便的应用。

发表评论: