您的位置:首页 > 编程语言 > Python开发

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)若有不足,请留言,在此先感谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: