Linux的socketpair()函数,是创建一对互相连接着的socket描述符。
类似TCP连接,两个文件描述符都可以读写,sv[0]写入的数据在sv[1]读出,sv[1]写入的数据在sv[0]读出。
它的参数与socket()类似,只是多了一个int sv[2]项用于返回这两个文件描述符,返回值用于提示创建是否成功。
而socket()函数的返回值就是文件描述符,用返回-1提示失败。
上图为它的man手册。
文件描述符,属于进程的资源之一,与进程的变量、代码类似,都会在fork()时被父子进程共享。
所以,socketpair()这个函数就被master+worker型的多进程服务器广泛用于master和各个worker的通信。
也可以用于子进程间的通信,因为第二个子进程被fork()时一样要共享父进程的socketpair,只要子进程间规定好谁使用1,谁使用2就行。
文件描述符在内核里对应着struct file结构,文件读写API最终都要处理内核的文件管理结构,文件描述符是这个结构的代号。
只要把某个文件的管理结构映射到某几个进程,他们就可以共享同一个文件了,在程序里的表现就是他们共享了同一对socketpair。
具体用法见如下三张图:
1,首先包含头文件“sys/types.h”和“sys/socket.h”,
2,然后在main()函数里先创建socketpair,然后再fork()子进程,这样子进程就共享了父进程的socketpair,
3,根据fork的返回值去判断出错、子进程、还是父进程,然后写不同的执行代码。
因为是进程间通信,所以使用AF_UNIX域(domain)的socket,类型选择SOCK_STREAM,类似TCP的可靠链接。
不要选SOCK_DGRAM,类似udp会在传输时丢包的。
我们在父进程里fork了第二个子进程,让这两个子进程互相通信,一个使用sv[1]发送,一个使用sv[0]接收。
他们把各自不用的那个sv[i]关掉,只保留用的那个。
发送字符串时带着结尾的’\0’,6个字符,因为strlen不计算结尾的’\0’,所以发送长度要加1。
这里发送数据使用了socket的send()和recv()函数,阻塞式调用。
他们也可以配合epoll()机制进行非阻塞式的调用,是nginx服务器的底层基础。
运行结果图:
PS:一个进程也可以在AF_UNIX域的socket上显式监听一个字符串表示的文件目录,等待其他进程去连接它,类似监听tcp的socket一样。
AF_UNIX的socketpair还可以把一个进程打开的文件,传递给另一个进程,这叫传递socket的附加数据,具体用法可以man一下cmsg。在Linux内核里就是把这个文件的管理结构struct file的指针加到目标进程的文件列表里。
举报/反馈