socketpair:【socket】 unix域套接字(socketpair )通信|socketpair和pipe的区别|进程间通信-Unix domain socket

 

目录

unix域套接字(socketpair )通信|socketpair和pipe的区别

socketpair机制

描述

原理

socketpair和pipe的区别

进程间通信-Unix domain socket


unix域套接字(socketpair )通信|socketpair和pipe的区别

2020-12-25 10:13:34

socketpair机制

描述

先看下传统的CS模型,如下:

总是一方发起请求,等待另一方回应。当一次传输完成之后,client端发起新的请求之后,server端才作出回应。 那如何才能做到双向通信?  一种解决办法就是client端即使client,又是server,server端即使client也是server,如下:

但是上述方面比较复杂,这时候就引入要分析的socketpair了。

socketpair用于创建一对相互连接的unnamed socket。而pipe系统调用使用创建的pipe也是相互连接的unnamed pipe(无名管道)。而pipe和socketpair创建的描述符之间的区别就是:  pipe创建的描述符一端只能用于读,一端用于写,而socketpair创建的描述符任意一端既可以读也可以写。

原理

示例代码:

#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$ ./socketpairHi, main process, cnt = 0Hi, thread process, cnt = 0Hi, main process, cnt = 1Hi, thread process, cnt = 1Hi, main process, cnt = 2Hi, thread process, cnt = 2

注意:  socketpair创建的只适用于父子进程或者线程间通信,不能用于两个进程之间通信。如果要实现两个进程之间的双向通信,则需要将socketpair创建的一个描述符fd发送给另一个进程,这相当于两个两个不同的进程访问同一个文件。

socketpair和pipe的区别

(原文:进程通信:管道(pipe)和socketpair区别_funpig的博客-CSDN博客_socketpair和pipe)

管道pipe是半双工的,pipe两次才能实现全双工,使得代码复杂。socketpair直接就可以实现全双工。

socketpair对两个文件描述符中的任何一个都可读和可写,而pipe是一个读,一个写。

详间代码:

一:pipe实现父子进程全双工通信:

#include <stdlib.h>#include <stdio.h> 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实现父子进程全双工通信:

#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() ) { /* 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

更多使用实例:《socketpair的用法和理解》socketpair的用法和理解_JohnWill_的博客-CSDN博客_socketpair

进程间通信-Unix domain socket

2020-04-24 19:24:09

 socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。

虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。

这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。

使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。

UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

Unix domain socket和TCP/IP之间有两个重要的不同。

1、socket的地址是文件路径,而不是一个包含ip和端口的元组。

2、在文件系统创建的代表socket的文件在socket关闭后依然存在,并且需要在每次服务器启动时删除。


server.py

import socketimport sysimport osSERVER_PATH = './uds_socket'# Make sure the socket does not already existif os.path.exists(SERVER_PATH): os.remove(SERVER_PATH)print >>sys.stderr ,'starting unix domain socket server'# Create a UDS socketsock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)# Bind the socket to the portsock.bind(SERVER_PATH)# Listen for incoming connssock.listen(2)print >>sys.stderr, 'Listening on path: %s' % SERVER_PATHwhile True: conn, addr = sock.accept() try: while True: data = conn.recv(1024) if data: print >>sys.stderr, 'received [%s]' % data conn.sendall(data) else: break except Exception,e: print e finally: conn.close()

client.py

import socketimport sys# Create a UDS socketsock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)# Connect the socket to the port where the server is listeningserver_address = './uds_socket'print >>sys.stderr, 'connecting to %s' % server_addresstry: sock.connect(server_address)except socket.error, msg: print >>sys.stderr, msg sys.exit(1) try: # Send data message = 'This is the message, This will be echoed back' print >>sys.stderr, 'sending [%s]' % message sock.sendall(message) amount_received = 0 amount_expected = len(message) while amount_received < amount_expected: data = sock.recv(1024) amount_received += len(data) print >>sys.stderr, 'received [%s]' % datafinally: print >>sys.stderr, 'closing socket' sock.close()

参考文章:https://www.jianshu.com/p/394dd8448400

Socket 用于进程间通信 --- UNIX Domain Socket - chekliang - 博客园

相关推荐

相关文章