问题
在windows环境主机A上想每隔15分钟获取远程Linux主机B上定时监控的logFile文件,但通过在A主机上:telnet B'ip port
(例:telnet 158.123.12.1 21)
查看远程主机没开放21
、22
端口,好像不能使用ftp
或者sftp
来获取(应该是不可以吧)。想自己写个简单服务器实现:
1、服务器端能够正确读取logFile内容
2、客户端访问时,服务器端能够返回logFile的内容
2、客户端能够正确获取logFile内容并写入本地文件中
解决
使用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()
-
ADDR
中PORT
为int
类型,要选取不冲突的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端HOST
、PROT
相同 -
def fileWrite(record, fileName)
:覆盖写入文件,注意如果该文件不存在会报错 -
tcpCliSock.send(data)
:发送消息给服务器端 -
tcpCliSock.recv(BUFSIZE)
:注意接收服务器端返回消息时,有可能超过BUFSIZE或者超过了MTU等限制,单次获取的记录不完整。所以使用TCP协议时,通过循环判断是否存在待接收消息,直到无消息时才断开连接
参考文章
Python核心编程(第3版)
TCP握手与socket通信细节
Python中使用socket发送HTTP请求数据接收不完整问题解决方法