1. 程式人生 > >Python例項淺談之九使用本地socket檔案

Python例項淺談之九使用本地socket檔案

       首先,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;
}