Python例項淺談之九使用本地socket檔案
阿新 • • 發佈:2019-02-07
首先,socket的連線地址是一個檔案的路徑而不是一個包含服務地址和埠號的元組;第二,當socket關閉後,socket檔案不會被刪除,該檔案代表一個永久的socket連線,所以每次伺服器啟動時,都需要手動刪除該檔案。第三,address family需要使用AF_UNIX而不是AF_INET,因為AF_UNIX會在bind時會生成一個檔案,而AF_INET不會。
(1)TCP/IP server
(2)TCP/IP clientimport 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()
(3)執行結果: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()
(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;
}