描述
先看下传统的CS模型,如下:
总是一方发起请求,等待另一方回应。当一次传输完成之后,client端发起新的请求之后,server端才作出回应。 那如何才能做到双向通信? 一种解决办法就是client端即使client,又是server,server端即使client也是server,如下:
但是上述方面比较复杂,这时候就引入要分析的socketpair了。
socketpair用于创建一对相互连接的unnamed socket。而pipe系统调用使用创建的pipe也是相互连接的unnamed pipe(无名管道)。而pipe和socketpair创建的描述符之间的区别就是: pipe创建的描述符一端只能用于读,一端用于写,而socketpair创建的描述符任意一端既可以读也可以写。
原理
使用socketpiar创建的是一对相互连接的socket,任意一段既可以做发送,也可以做接受端。所有每个socket描述符中应该有两个buf。一个为发送buf,一个为接受buf。如上图所示。
示例代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>#define SOCKET_BUFFER_SIZE (32768U)void *thread_function(void *arg)
{int len = 0;int fd = *((int*)(arg));char buf[500];int cnt = 0;/*主线程*/while(1){ /*向main thread线程发送数据*/len = sprintf(buf, "Hi, main process, cnt = %d", cnt++);write(fd, buf, len);/*读数据*/len = read(fd, buf, 500);buf[len]='\0';printf("%s\n",buf);sleep(5); } return NULL;
}int main()
{int ret;int sockets[2];int bufferSize = SOCKET_BUFFER_SIZE;pthread_t thread;ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets);if(ret == -1){printf("socketpair create error!\n");return -1;}/*设置socket描述符的选项*/setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));/*创建线程1*/pthread_create(&thread, NULL, thread_function, (void*)(&sockets[1]));int len = 0;int fd = sockets[0];char buf[500];int cnt = 0;/*主线程*/while(1){/*读数据*/len = read(fd, buf, 500);buf[len]='\0';printf("%s\n",buf);/*项thread线程发送数据*/len = sprintf(buf, "Hi, thread process, cnt = %d", cnt++);write(fd, buf, len);}return 0;
}
测试结果:
1. 编译代码
gcc socketpair.c -o socketpair -lpthread
2. 运行,查看结果
test$ ./socketpair
Hi, main process, cnt = 0
Hi, thread process, cnt = 0
Hi, main process, cnt = 1
Hi, thread process, cnt = 1
Hi, main process, cnt = 2
Hi, thread process, cnt = 2
注意: socketpair创建的只适用于父子进程或者线程间通信,不能用于两个进程之间通信。如果要实现两个进程之间的双向通信,则需要将socketpair创建的一个描述符fd发送给另一个进程,这相当于两个两个不同的进程访问同一个文件。