Python socket服務器端、客戶端傳送信息

問題

windows環境主機A上想每隔15分鐘獲取遠程Linux主機B上定時監控的logFile文件,但經過在A主機上:telnet B'ip port (例:telnet 158.123.12.1 21)查看遠程主機沒開放2122端口,好像不能使用ftp或者sftp來獲取(應該是不能夠吧)。想本身寫個簡單服務器實現:
一、服務器端可以正確讀取logFile內容
二、客戶端訪問時,服務器端可以返回logFile的內容
二、客戶端可以正確獲取logFile內容並寫入本地文件中python

解決

使用Python的socket模塊,本身新增一個能夠直接訪問的PORT。爲了保證數據準確性,使用比較簡單的方法:客戶端與服務器端經過TCP方式通訊。服務器端先啓動後,循環等待客戶端訪問。因爲是單個客戶端每隔15分鐘訪問,每完成一次訪問便斷開鏈接,因此採用了單線程阻塞的方法實現的服務器端:編程

遠程Linux主機B 服務器端代碼:
#coding=utf-8
    #!/usr/bin/python
    
    from socket import *
    
    HOST = '158.123.12.1'
    PORT = 8083
    BUFSIZE = 65535
    ADDR = (HOST, PORT)
    
    tcpSerSock = socket(AF_INET, SOCK_STREAM)
    tcpSerSock.bind(ADDR)
    tcpSerSock.listen(5)
    
    welcomeStr = 'Welcome to 12.1 python socket server'
    
    def logFileRead(logFile):
        '''
        Read logFile by line
        return List
        '''
        logFileDealList = []
        with open(logFile, 'r') as logFileContent:
            for line in logFileContent.readlines():
                logFileDealList.append(line)
        return logFileDealList
    
    if __name__ == "__main__":
        fileDir = 'filePath/warningMessage.txt'
    
        while True:
            print 'Enter 12.1 python socket server'
            tcpCliSock, addr = tcpSerSock.accept()
            print 'Connected from : ', addr
            data = tcpCliSock.recv(BUFSIZE)
    
            if not data:
                break
            print data
            logFileContentList = logFileRead(fileDir)
            # print logFileContentList
            for fileContent in logFileContentList:
                if fileContent.find('pending') == -1:
                    continue
                tcpCliSock.send('%s' % fileContent)
            tcpCliSock.close()
    
        tcpSerSock.close()
  • ADDRPORTint類型,要選取不衝突的PORT,在Linux上能夠經過netstat -anp | grep PORT'id 例:netstat -anp | grep 8083,查看端口號佔用狀況。
  • socket(AF_INET, SOCK_STREAM):使用HOST+PORT時,要使用AF_INET網絡協議搜索主機(也可使用 TCP 和本地[非網絡的 AF_LOCAL/AF_UNIX]套接字,可是很明顯此時並無使用 IP);使用TCP方式時,要使用SOCK_STREAM基於流套接字(建立 UDP 套接字,必須使用SOCK_DGRAM做爲套接字類型)。
  • bind(ADDR):將地址(主機名、端口號對)綁定到套接字上
  • listen(5):設置並啓動TCP監聽器,參數5是在鏈接被轉接或拒絕以前,傳入鏈接請求的最大數鏈接隊列最大值。若是Client端請求超過5個,Linux中Server會延遲到鏈接數低於5時響應鏈接。未測試過,具體處理流程能夠參考:TCP握手與socket通訊細節。因爲當前只有一個Client客戶端,因此5足夠使用。
  • def logFileRead(logFile):讀取文件的function
  • accept():被動接受TCP客戶端鏈接,持續等待直到鏈接到達(阻塞等待)
  • tcpCliSock.recv(BUFSIZE):接收TCP消息,BUFSIZE定義的爲緩衝區大小。接收的是Client端傳送過來的消息。
  • tcpCliSock.send('%s' % fileContent):發送TCP消息,將結果返回給Client段
  • tcpCliSock.close():關閉客戶端鏈接
  • tcpSerSock.close():退出服務器端
  • 執行時,能夠將Server端掛載到後臺不退出
本地Windows主機A 客戶端代碼:
#coding=utf-8
    #!/usr/bin/python
    
    from socket import *
    
    HOST = '158.123.12.1'
    PORT = 8083
    BUFSIZE = 65535
    ADDR = (HOST, PORT)
    
    welcomeStr = 'Welcome to 12.1 python socket server'
    
    def fileWrite(record, fileName):
         with open(fileName, 'w') as logFile:
            for recordItem in record:
                logFile.write(recordItem)
    
    def main():
        tcpCliSock = socket(AF_INET, SOCK_STREAM)
        tcpCliSock.connect(ADDR)
        fileDir = 'filePath/warnLogFile.txt'
        print 'Will connect 12.1 python socket server'
        data = 'hello'
        tcpCliSock.send(data)
    
        retDataAll = ''
    
        while True:
            retDataTmp = tcpCliSock.recv(BUFSIZE)
            if not retDataTmp:
                break
            if not len(retDataTmp):
                break
            print retDataTmp
            retDataAll = retDataAll + retDataTmp
        print 'end '
        tcpCliSock.close()
        fileWrite(retDataAll, fileDir)
    
    if __name__ == '__main__':
        main()
  • ADDR = (HOST, PORT):與Server端HOSTPROT相同
  • def fileWrite(record, fileName):覆蓋寫入文件,注意若是該文件不存在會報錯
  • tcpCliSock.send(data):發送消息給服務器端
  • tcpCliSock.recv(BUFSIZE):注意接收服務器端返回消息時,有可能超過BUFSIZE或者超過了MTU等限制,單次獲取的記錄不完整。因此使用TCP協議時,經過循環判斷是否存在待接收消息,直到無消息時才斷開鏈接

參考文章

Python核心編程(第3版)
TCP握手與socket通訊細節
Python中使用socket發送HTTP請求數據接收不完整問題解決方法windows

相關文章
相關標籤/搜索