Python实例浅谈之九使用本地socket文件
2015-07-06 16:26
567 查看
一、简介
Unix domain socket(unix域协议)是在单个主机上执行客户/服务器通信的一种方法,是进程之间本地通信IPC的一种。它提供面向流和面向数据包两种API接口,类似于TCP和UDP,面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。因需要使用本地socket文件进行通信,故总结了该部分内容。
二、详解
1、Python服务器和客户端
首先,socket的连接地址是一个文件的路径而不是一个包含服务地址和端口号的元组;第二,当socket关闭后,socket文件不会被删除,该文件代表一个永久的socket连接,所以每次服务器启动时,都需要手动删除该文件。第三,address family需要使用AF_UNIX而不是AF_INET,因为AF_UNIX会在bind时会生成一个文件,而AF_INET不会。(1)TCP/IP server
import socket import sys import os server_address = './uds_socket' # Make sure the socket does not already exist try: os.unlink(server_address) except OSError: if os.path.exists(server_address): raise # Create a UDS socket sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) # Bind the socket to the port print >>sys.stderr, 'starting up on %s' % server_address sock.bind(server_address) # Listen for incoming connections sock.listen(1) while True: # Wait for a connection print >>sys.stderr, 'waiting for a connection' connection, client_address = sock.accept() try: print >>sys.stderr, 'connection from', client_address # Receive the data in small chunks and retransmit it while True: data = connection.recv(16) print >>sys.stderr, 'received "%s"' % data if data: print >>sys.stderr, 'sending data back to the client' connection.sendall(data) else: print >>sys.stderr, 'no more data from', client_address break finally: # Clean up the connection connection.close()(2)TCP/IP client
import socket import sys # Create a UDS socket sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # Connect the socket to the port where the server is listening server_address = './uds_socket' print >>sys.stderr, 'connecting to %s' % server_address try: sock.connect(server_address) except socket.error, msg: print >>sys.stderr, msg sys.exit(1) try: # Send data message = 'This is the message. It will be repeated.' print >>sys.stderr, 'sending "%s"' % message sock.sendall(message) amount_received = 0 amount_expected = len(message) while amount_received < amount_expected: data = sock.recv(16) amount_received += len(data) print >>sys.stderr, 'received "%s"' % data finally: print >>sys.stderr, 'closing socket' sock.close()(3)运行结果:
(4)可以控制多socket文件的访问权限
(5)父子进程间通信
socketpair()创建一对连接socket,用于父子进程间的通信。
import socket import os parent, child = socket.socketpair() pid = os.fork() if pid: print 'in parent, sending message' child.close() parent.sendall('ping') response = parent.recv(1024) print 'response from child:', response parent.close() else: print 'in child, waiting for message' parent.close() message = child.recv(1024) print 'message from parent:', message child.sendall('pong') child.close()
2、C++服务器和客户端
使用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()错误返回。
(1)tcp_server.c:
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> int main() { /* delete the socket file */ unlink("server_socket"); /* create a socket */ int server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un server_addr; server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, "server_socket"); /* bind with the local file */ bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); /* listen */ listen(server_sockfd, 5); char ch; int client_sockfd; struct sockaddr_un client_addr; socklen_t len = sizeof(client_addr); while(1) { printf("server waiting:\n"); /* accept a connection */ client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len); /* exchange data */ read(client_sockfd, &ch, 1); printf("get char from client: %c\n", ch); ++ch; write(client_sockfd, &ch, 1); /* close the socket */ close(client_sockfd); } return 0; }(2)tcp_client.c:
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> int main() { /* create a socket */ int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un address; address.sun_family = AF_UNIX; strcpy(address.sun_path, "server_socket"); /* connect to the server */ int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); if(result == -1) { perror("connect failed: "); exit(1); } /* exchange data */ char ch = 'A'; write(sockfd, &ch, 1); read(sockfd, &ch, 1); printf("get char from server: %c\n", ch); /* close the socket */ close(sockfd); return 0; }(3)运行结果:
3、Qt下的UDS客户端
QString HostConnectVM::getResult(QString command, QString socketFile) { QString resultStr = ""; QFileInfo fileInfo(socketFile); if (!fileInfo.exists()) { qDebug() << "socketFile do not exist, please set socketfile first"; resultStr = "error5"; return resultStr; } /* create a socket */ struct sockaddr_un address; address.sun_family = AF_UNIX; strcpy(address.sun_path, socketFile.toStdString().data()); int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd == -1) { qDebug() << "create socket failed"; resultStr = "error1"; return resultStr; } /* connect to the server */ int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); if(result == -1) { qDebug() << "connect socket failed"; resultStr = "error2"; return resultStr; } if((result = write(sockfd, command.toStdString().data(), command.length())) != command.length()) { qDebug() << "write socket failed"; resultStr = "error3"; return resultStr; } char buff[10240] = {0}; if ((result = read(sockfd, buff, 10240)) == -1) { qDebug() << "read socket failed"; resultStr = "error4"; return resultStr; } resultStr = buff; resultStr = resultStr.trimmed(); close(sockfd); return resultStr; }
三、总结
(1)可参考文章http://pymotw.com/2/socket/uds.html和http://blog.csdn.net/bingqingsuimeng/article/details/8470029(2)还需根据实际应用使用不同的代码,上述代码也须不断的完善调整。
(3)若有不足,请留言,在此先感谢!
相关文章推荐
- python3.4学习笔记(十六) windows下面安装easy_install和pip教程
- [置顶] python多进程多核利用心得体验
- python的动态导入module和class
- 如何采用Python zabbix_api 获取性能数据
- python entry points 例子
- python的字典
- qemu guest agent修改密码(python)
- 浅谈 Python 的 with 语句
- 用PyInstaller把Python代码打包成单个独立的exe可执行文件
- 理解Python的With语句
- Python 学习 --- 基础知识
- 判断Python输入是否为数字
- Python实现图像几何变换
- Python统计日志中每个IP出现次数的方法
- python BinaryTree
- python统计日志ip访问数的方法
- python检查指定文件是否存在的方法
- vim的python代码检测工具
- windows上安装numpy和scipy
- 安装python至windows