首页 > 脚本语言 > python > Python实例浅谈之九使用本地socket文件
2015
07-24

Python实例浅谈之九使用本地socket文件

一、简介

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 
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)运行结果:
Python实例浅谈之九使用本地socket文件 - 第1张  | 大话运维Python实例浅谈之九使用本地socket文件 - 第2张  | 大话运维

(4)可以控制多socket文件的访问权限

Python实例浅谈之九使用本地socket文件 - 第3张  | 大话运维

(5)父子进程间通信

socketpair()创建一对连接socket,用于父子进程间的通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
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()

Python实例浅谈之九使用本地socket文件 - 第4张  | 大话运维

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
#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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
#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)运行结果:

Python实例浅谈之九使用本地socket文件 - 第5张  | 大话运维

3、Qt下的UDS客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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;
}
最后编辑:
作者:saunix
大型互联网公司linux系统运维攻城狮,专门担当消防员

留下一个回复