简体   繁体   English

在连续运行的python脚本中保持端口打开

[英]Keeping ports open in a python script that is run continuously

I'm trying to develop a server script using python 3.4 that runs perpetually and responds to client requests on up to 5 separate ports. 我正在尝试使用python 3.4开发服务器脚本,该脚本可以永久运行并在多达5个单独的端口上响应客户端请求。 My preferred platform is Debian 8.0. 我首选的平台是Debian 8.0。 The platform currently runs on a virtual machine in the cloud. 该平台当前在云中的虚拟机上运行。 My script works fine when I run it off the command line - I need to now (1) keep it running once I log off the server and (2) keep several ports open through the script so that a windows client can connect to them. 当我从命令行运行脚本时,我的脚本可以正常工作-我现在需要(1)从服务器注销后使其继续运行,以及(2)通过该脚本保持几个端口打开,以便Windows客户端可以连接到它们。

For (1), 对于(1),

After trying several options [I tried using upstart, added the script to rc.local, used nohup with & to run it off the terminal, etc] that didn't seem to work, I eventually found something that does seem to keep the script running, even if it's not very elegant - I wrote an hourly cron script that checks to see if the script is running in the process list, and if not, to execute it. 尝试了几种选项后[似乎没有用] [我尝试使用upstart,将脚本添加到rc.local,将nohup与&一起使用,以在终端上运行它,等等],我最终发现了一些似乎可以保留该脚本的东西即使它不是很优雅,也可以运行-我编写了一个每小时的cron脚本,检查该脚本是否正在进程列表中运行,如果不运行,则执行该脚本。

Whenever I login to the VM now, I see the following output when I type 'ps -ef': 现在无论何时登录虚拟机,在键入“ ps -ef”时都会看到以下输出:

root 22007 21992 98 Nov10 14-12:52:59 /usr/bin/python3.4 /home/userxyz/cronserver.py 根22007 21992 98 Nov10 14-12:52:59 /usr/bin/python3.4 /home/userxyz/cronserver.py

I assume that the script is running based on the fact that there is an active process in the system. 我假设脚本正在运行是基于系统中存在活动进程这一事实。 I mention this part because I suspect that there could be a correlation with part (2) of my issue. 我之所以提到这一部分,是因为我怀疑问题的第二部分可能存在关联。

For (2), 对于(2),

The script is supposed to open ports 49100 - 49105 and listen for connection requests, etc. When I run the script from the terminal, zenmap from my client machine verifies that these ports are open. 该脚本应该打开端口49100-49105并侦听连接请求等。当我从终端运行脚本时,客户端计算机上的zenmap会验证这些端口是否打开。 However, when the cron job initiates the script, these ports don't seem to stay open. 但是,当cron作业启动脚本时,这些端口似乎没有保持打开状态。 My windows client program can't connect to the script either. 我的Windows客户端程序也无法连接到脚本。

The python code I use for listening to a port: 我用于侦听端口的python代码:

    f = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    f.bind((serviceIP, 49101))
    f.listen(5)
    while True:
            scName, address = f.accept()

            [code to handle request]

            scName.shutdown(socket.SHUT_WR)
            scName.close()

Any insight or assistance would be greatly appreciated! 任何见解或协助将不胜感激!

What you ask is not easy because it depends on a variety of factors: 您的要求并不容易,因为它取决于多种因素:

  • What is the frequency of the data received? 接收数据的频率是多少?
  • How many clients are expected to connect to this server? 预计有多少客户端连接到该服务器?
    • Is there a chance two clients try to connect at the same time? 是否有两个客户端尝试同时连接的机会?
  • How long it takes to handle some received data? 处理一些接收到的数据需要多长时间?
  • What do you need to do with your data? 您需要如何处理您的数据?
    • Write to a database? 写入数据库?
    • Write to a file? 写入文件?
    • Calculate something? 计算什么?
  • Etc. 等等。

Depending on your answer you'll have some design decisions to make for your solution. 根据您的答案,您将为您的解决方案做出一些设计决策。

But since you need an answer, here's a hack that represent a way to do things: 但是,由于您需要答案,因此这里有一个骇客,代表一种做事方式:

import socketserver
import threading
import datetime

class SleepyGaryReceptionHandler(socketserver.BaseRequestHandler):

    log_file_name = "/tmp/sleepygaryserver.log"

    def handle(self):

        # self.request is defined in BaseRequestHandler
        data_received = self.request.recv(1024)
        # self.client_address is also defined in BaseRequestHandler
        sender_address = self.client_address[0]

        # This is where you are supposed to do something with your data
        # This is an example
        self.write_to_log('Someone from {} sent us "{}"'.format(sender_address,
                                                                data_received))

        # A way to stop the server from going on forever
        # But you could do this other ways but it depends what condition
        # should cause the shutdown
        if data_received.startswith(b"QUIT"):
            finishing_thread = threading.Thread(target=self.finish_in_another_thread)
            finishing_thread.start()

    # This will be called in another thread to terminate the server
    # self.server is also defined in BaseRequestHandler
    def finish_in_another_thread(self):
        self.write_to_log("Shutting down the server")
        self.server.shutdown()

    # Write something (with a timestamp) to a text file so that we
    # know something is happenning
    def write_to_log(self, message):
        timestamp = datetime.datetime.now()
        timestamp_text = timestamp.isoformat(sep=' ', timespec='seconds')
        with open(self.log_file_name, mode='a') as log_file:
            log_file.write("{}: {}\n".format(timestamp_text, message))

service_address = "localhost"
port_number = 49101

server = socketserver.TCPServer((service_address, port_number),
                                SleepyGaryReceptionHandler)
server.serve_forever()

I'm using here the socketserver module instead of listening directly at a socket. 我在这里使用socketserver模块,而不是直接在套接字上侦听。 This standard library module has been written to simplify writing a server. 编写此标准库模块是为了简化服务器的编写。 so use it! 所以用吧!

All I do here is write to a text file what has been received. 我在这里所做的只是将收到的内容写入文本文件。 You would have to adapt it to your use. 您将不得不使其适应您的使用。

But to have it running continuously use a cron job but to start it at the startup of the computer. 但是要使其连续运行,请使用cron作业,而要在计算机启动时将其启动。 Since this script will block until the server is stopped, we have to run it in the background. 由于此脚本将阻塞直到服务器停止,因此我们必须在后台运行它。 It would look something like that: 它看起来像这样:

 @reboot /usr/bin/python3 /home/sleepygary/sleppys_server.py &

I have tested it and after 5 hours it still does his thing. 我已经对其进行了测试,并且在5个小时后仍然可以完成他的工作。

Now like I said, it is a hack. 现在就像我说的,这是一个hack。 If you want to go all the way and do things like any other services on your computer you have to program it in a certain way. 如果您想一路走下去,并且要像计算机上的其他服务一样执行操作,则必须以某种方式对其进行编程。 You can find more information on this page: https://www.freedesktop.org/software/systemd/man/daemon.html 您可以在此页面上找到更多信息: https : //www.freedesktop.org/software/systemd/man/daemon.html

I'm really tired so there may be some errors here and there. 我真的很累,所以这里和那里可能有一些错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM