当前位置: 首页 > news >正文

Python socket服务器端、客户端传送信息

问题

windows环境主机A上想每隔15分钟获取远程Linux主机B上定时监控的logFile文件,但通过在A主机上:telnet B'ip port (例:telnet 158.123.12.1 21)查看远程主机没开放2122端口,好像不能使用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()
  • 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请求数据接收不完整问题解决方法

相关文章:

  • Unity3D加密外壳如何做到防止反编译?
  • PHP二维关联数组的遍历方式
  • SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
  • 大型软件公司.Net面试题(一)
  • Eclipse-Java代码规范和质量检查插件-FindBugs
  • uploadify是通过flash上传,服务器获取type为application/octet-stream
  • 使用putty连接linux
  • 深度讲解 Android 主题层级
  • Percona XtraBackup 实现全备增量备份与恢复【转】
  • 中国的软件人才是靠挖的
  • mvn 主要命令说明
  • Servlet获取ajax数组
  • 小程序测试方案初探
  • 注册界面
  • PDF 补丁丁 0.6.0.3288 版发布(修复“合并文件”功能的文件夹文件排序问题)
  • 「面试题」如何实现一个圣杯布局?
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • CentOS7 安装JDK
  • es6要点
  • flask接收请求并推入栈
  • JavaScript DOM 10 - 滚动
  • js算法-归并排序(merge_sort)
  • JS字符串转数字方法总结
  • PAT A1050
  • PHP面试之三:MySQL数据库
  • Rancher如何对接Ceph-RBD块存储
  • Redis中的lru算法实现
  • SpringBoot 实战 (三) | 配置文件详解
  • 如何使用 JavaScript 解析 URL
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 手写一个CommonJS打包工具(一)
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • 一个完整Java Web项目背后的密码
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 阿里云重庆大学大数据训练营落地分享
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • #include
  • #pragma pack(1)
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (AngularJS)Angular 控制器之间通信初探
  • (NSDate) 时间 (time )比较
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (八十八)VFL语言初步 - 实现布局
  • (二)正点原子I.MX6ULL u-boot移植
  • (九)c52学习之旅-定时器
  • (三)模仿学习-Action数据的模仿
  • (四)Controller接口控制器详解(三)
  • (四)Linux Shell编程——输入输出重定向
  • (转)IOS中获取各种文件的目录路径的方法
  • ..回顾17,展望18
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .net 7 上传文件踩坑