socketpair机制
描述
先看下传统的CS模型,如下:
总是一方发起请求,等待另一方回应。当一次传输完成之后,client端发起新的请求之后,server端才作出回应。 那如何才能做到双向通信? 一种解决办法就是client端即使client,又是server,server端即使client也是server,如下:
但是上述方面比较复杂,这时候就引入要分析的socketpair了。
socketpair用于创建一对相互连接的unnamed socket。而pipe系统调用使用创建的pipe也是相互连接的unnamed pipe(无名管道)。而pipe和socketpair创建的描述符之间的区别就是: pipe创建的描述符一端只能用于读,一端用于写,而socketpair创建的描述符任意一端既可以读也可以写。
原理
示例代码:
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发送给另一个进程,这相当于两个两个不同的进程访问同一个文件。
socketpair和pipe的区别管道pipe是半双工的,pipe两次才能实现全双工,使得代码复杂。socketpair直接就可以实现全双工。
socketpair对两个文件描述符中的任何一个都可读和可写,而pipe是一个读,一个写。
详间代码:
一:pipe实现父子进程全双工通信:
int main ()
{
int fd1[2],fd2[2];
pipe(fd1);
pipe(fd2);
if ( fork() ) {
/* Parent process: echo client */
int val = 0;
close( fd1[0] );
close(fd2[1]);
while ( 1 ) {
sleep( 1 );
++val;
printf( "parent Sending data: %d\n", val );
write( fd1[1], &val, sizeof(val) );
read( fd2[0], &val, sizeof(val) );
printf( "parent Data received: %d\n", val );
}
}
else {
/* Child process: echo server */
int val ;
close( fd1[1] );
close(fd2[0]);
while ( 1 ) {
read( fd1[0], &val, sizeof(val) );
printf( "son Data received: %d\n", val );
++val;
write( fd2[1], &val, sizeof(val) );
printf( "son send received: %d\n", val );
}
}
}
输出结果:parent Sending data: 1
son Data received: 1
son send received: 2
parent Data received: 2
parent Sending data: 3
son Data received: 3
son send received: 4
parent Data received: 4
一:soketpair实现父子进程全双工通信:
int main ()
{
int fd[2];
int r = socketpair( AF_UNIX, SOCK_STREAM, 0, fd );
if ( r < 0 ) {
perror( "socketpair()" );
exit( 1 );
}
if ( fork() ) {
/* Parent process: echo client */
int val = 0;
close( fd[1] );
while ( 1 ) {
sleep( 1 );
++val;
printf( "parent Sending data: %d\n", val );
write( fd[0], &val, sizeof(val) );
read( fd[0], &val, sizeof(val) );
printf( "parent Data received: %d\n", val );
}
}
else {
/* Child process: echo server */
int val ;
close( fd[0] );
while ( 1 ) {
read( fd[1], &val, sizeof(val) );
printf( "son Data received: %d\n", val );
++val;
write( fd[1], &val, sizeof(val) );
printf( "son send received: %d\n", val );
}
}
}
输出结果:parent Sending data: 1
son Data received: 1
son send received: 2
parent Data received: 2
parent Sending data: 3
son Data received: 3
son send received: 4
parent Data received: 4