【问题标题】:How do I close an open socket on app exit如何在应用退出时关闭打开的套接字
【发布时间】:2018-06-19 21:30:18
【问题描述】:

我开始学习构建server client apps,发现了一个不错的example 我的最终目标是将文件从服务器传输到客户端并在应用程序上绘制接收到的数据。

我在这里建立了一个示例应用程序。有人可以建议在退出应用程序时如何调用close socket 函数吗?

我假设只需要在程序exit 上关闭套接字,而不是在每次文件传输之后。因此我把关闭套接字的代码放在最后。

我想过在ClientAPP 类中使用on_stop。但由于尚未创建变量,因此从那里引用函数似乎是不可能的。

我正在遵循here 的答案之一的建议:

server.py

# -*- coding: utf-8 -*-

import socket
from threading import Thread

class Server(object):
    def __init__(self):
        #Creates socket object
        self.serversocket = socket.socket()

        self.host = 'localhost'
        self.port = 54545

    #If we had used s.bind(('localhost', 80)) or s.bind(('127.0.0.1', 80)) we would still have a �server� socket, but one that was only visible within the same machine. s.bind(('', 80)) specifies that the socket is reachable by any address the machine happens to have.

    def start_server(self):
        self.serversocket.bind(('', self.port))

        self.serversocket.listen(10)

        self.clientsocket, self.addr = self.serversocket.accept()
        print("got a connection from %s" % str(self.addr))

        confirmation = 'Connected'
        self.clientsocket.send(confirmation.encode())

        #start_listening
        Thread(target=self.print_received_client_data).start()

    def print_received_client_data(self):
        while True:
            print('Received from client: %s' % self.clientsocket.recv(1024).decode())        

if __name__=="__main__":
    Server().start_server()

ClientAPP.py

# -*- coding: utf-8 -*-

from kivy.app import App
from kivy.uix.label import Label
from threading import Thread
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
import socket, time
from kivy.uix.screenmanager import Screen, ScreenManager

class ScreenManagement(ScreenManager):
    pass

class HomeScreen(Screen):
    def __init__(self, **kwargs):
        super(HomeScreen,self).__init__(**kwargs)

        self.sock_instance = MySocket()
        Thread(target=self.set_text_input).start()

    host = "localhost"
    port = 7000
    display = ObjectProperty()

    def set_text_input(self):
        while True:
            time.sleep(0.1)
            self.text = self.sock_instance.get_data()                  

    def send_message(self):  
        #self.ids.display.text is encoded and sent            
        self.sock_instance.sock.send(self.ids.display.text.encode()) 

    def receive_message(self):
        # Decodes a reply, Converts it to a str, prints it           
        print("Message from server - %s" % str(self.sock_instance.sock.recv(1024).decode("ascii")))

class SettingsScreen(Screen):
    pass

class MySocket:

    def __init__(self, host="localhost", port=54545):

        self.sock = socket.socket()
        self.sock.connect((host, port))

        #Receives confirmation from Server, Converts to string, Prints confirmation
        print("%s" % str(self.sock.recv(1024).decode()))         

    def get_data(self):
        return self.sock.recv(1024)

    def close_socket(self):
        self.sock.close()

class ClientAPP(App):

    def build(self):
        runtime_instance = ScreenManagement()
        return runtime_instance

if __name__ == '__main__':
    app_instance = ClientAPP()
    try:
        app_instance.run()
    finally:
        #Code to close socket here, ideally, call close_socket
        print("Closed the socket")

ClientAPP.kv

#: import FadeTransition kivy.uix.screenmanager.FadeTransition

<ScreenManagement>:
    transition:FadeTransition()
    HomeScreen:
    SettingsScreen:

<HomeScreen>:
    RelativeLayout:
        Button:
            size_hint: 0.2,0.2
            pos_hint:{"x":0,"y":0.4}
            text: "Send Message"
            on_press: root.send_message()
        TextInput:
            id: display
            size_hint: 0.2,0.2
            pos_hint:{"x":0.2,"y":0.4}
            text: "abc"

编辑 - 之前发布的 server.py 不正确

【问题讨论】:

  • 当您到达 finally 语句时,您的服务器线程和相关对象将失效,因此您将无法访问套接字。您必须在后台线程终止之前执行此操作。

标签: python kivy


【解决方案1】:

解决方案

关闭套接字 - 当窗口关闭时,即点击 X

  1. 添加导入语句,from kivy.core.window import Window
  2. 将Window.bind(on_request_close=self.close_socket) 添加到MySocket: 类的__init__() 方法中。

关闭套接字 - 退出应用程序时

  1. 在kv文件中,添加id: home_screen
  2. 在 Python 文件中,将on_stop() 事件和调用close_socket() 方法添加到ServerApp() 和ClientApp() 类中。

kv 文件 - 添加 id

server.kv & client.kv

<ScreenManagement>:
    HomeScreen:
        id: home_screen
        name: 'home_screen'
    SettingsScreen:
        name: 'settings_screen'

Python 文件

server.py

​​>
class MySocket:

    def __init__(self, host="localhost", port=54545):
        Window.bind(on_request_close=self.close_socket)

    ...

    def close_socket(self, *largs, **kwargs):
        print("\nServerApp.close_socket:")
        print("\tClosed the socket")
        self.sock.close()


class ServerApp(App):

    def build(self):
        self.runtime_instance = ScreenManagement()
        return self.runtime_instance

    def on_stop(self):
        print('\nServerApp.on_stop:')
        self.runtime_instance.ids.home_screen.sock_instance.close_socket()


if __name__ == '__main__':
    ServerApp().run()

main.py

​​>
class MySocket:

    def __init__(self, host="localhost", port=54545):
        Window.bind(on_request_close=self.close_socket)

    ...

    def close_socket(self, *largs, **kwargs):
        print("\nClientApp.close_socket:")
        print("\tClosed the socket")
        self.sock.close()

class ClientApp(App):

    def build(self):
        self.runtime_instance = ScreenManagement()
        return self.runtime_instance

    def on_stop(self):
        print('\nClientApp.on_stop:')
        self.runtime_instance.ids.home_screen.sock_instance.close_socket()


if __name__ == '__main__':
    ClientApp().run()

输出

ServerApp 发送数据

ClientApp 收到数据

ServerApp 退出

【讨论】:

  • 嘿,谢谢你的好回答 :) 分配一个 ID 并调用,从而调用函数。我错误地发布了错误的server.py。我对 ClientAPP.py 实施了您的建议。使用窗口工作。套接字现在正在关闭时关闭。也添加“从 kivy.core.window 导入窗口”。对于其他阅读帖子的人。我现在有一个新问题。当我关闭客户端应用程序并尝试再次打开它时,ClientAPP 挂起。大概它无法再次连接到服务器。知道可能出了什么问题吗?
  • 将等待连接的语句,即self.clientsocket, self.addr = self.serversocket.accept()放在一个循环中,然后再接收/发送数据(嵌套循环)。
  • 像魅力一样工作 :) 谢谢
猜你喜欢
  • 2020-05-04
  • 1970-01-01
  • 1970-01-01
  • 2016-02-14
  • 2014-02-15
  • 1970-01-01
  • 2014-09-18
  • 2017-12-24
  • 1970-01-01
相关资源
最近更新 更多