Search code examples
pythonsocketskivy

Why does my code doesnt work when connecting with server in a function but works okay when I called the connection using __init__?


I am trying to establish a connection with a server with a button instead of trying it when the application starts. I tried initializing the client class in "MySocket" in the "TitleWindow" and it works fine but when I tried the same thing with a function call my "self.sock" in the function "get_data" and "send_data" turns into None

This code works fine.

class TitleWindow(Screen):
    def __init__(self, **kwargs):
        super(TitleWindow, self).__init__(**kwargs)
        self.text = 0
        self.send_text = 0
        try:
            self.sock = MySocket()
            Thread(target=self.send_data).start()
            Thread(target=self.get_data).start()
            self.manager.current = "main"
            self.manager.transition.direction = "left"
        except Exception as e:
            print(str(e))
            print("No Connection to server")
            self.manager.current = "connect"
            self.manager.transition.direction = "left"

    def get_data(self):
        while True:
                self.text = self.sock.get_data()
                print(self.text.decode('utf-8'))
                return self.text


    def send_data(self, msg=None):
        while True:
                # msg = input()
                self.sock.send_data(msg)
                break

But this does not?

class TitleWindow(Screen):  # connection to server may start here
    def __init__(self, **kwargs):
        super(TitleWindow, self).__init__(**kwargs)
        self.sock = None
        self.text = 0
        self.send_text = 0

    def next_screen(self):
        self.manager.current = "main"
        self.manager.transition.direction = "up"

    def connection(self):
        try:
            self.sock = MySocket()
            print(self.sock)
            Thread(target=self.send_data).start()
            Thread(target=self.get_data).start()
            self.manager.current = "main"
            self.manager.transition.direction = "left"
        except Exception as e:
            print(str(e))
            sleep(0.1)
            self.manager.current = "connect"
            self.manager.transition.direction = "left"

    def get_data(self):
        while True:
                self.text = self.sock.get_data()
                print(self.text.decode('utf-8'))
                return self.text
          

    def send_data(self, msg=None):
        while True:
                # msg = input()
                self.sock.send_data(msg)
                break


This is the client program where i establish the socket(client.py)

class MySocket:

    #def __init__(self, host="133.54.230.187", port=8000):
    def __init__(self, host="localhost", port=54545):
        self.sock = socket.socket()
        self.sock.connect((host, port))
        print("Connected")


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

    def send_data(self, send_msg):
        self.sock.send(send_msg.encode())



my.kv

<WindowManager>:
    TitleWindow:
    ConnectionWindow:
    MainWindow:

<MainWindow>:
    name : "main"
    FloatLayout:
    Button :
            pos_hint : {"x":0.45,"y":0.3}
            text : "Start"
            on_release :
                root.data_call()




<TitleWindow>:
    name : "title"
    Label :
        id:title_label
        text : "WELCOME!"
        pos_hint : {"center_x" : 0.5 , "center_y" : 0.5}




    Button :
        text : "Proceed"
        pos_hint : {"center_x" : 0.5 , "center_y" : 0.25}
        on_release :
            root.connection()

<ConnectionWindow>
    name : "connect"
    Label :
        id:connect_label
        text : "Server is not available, please reconfigure the device..."
        pos_hint : {"center_x" : 0.5 , "center_y" : 0.5}
    Button :
        id : return
        text : "Return"
        pos_hint : {"center_x" : 0.25 , "center_y" : 0.25}
        disabled : False
        on_release :
            root.top()
    Button :
        id : recon_button
        text : "Proceed"
        pos_hint : {"center_x" : 0.75 , "center_y" : 0.25}
        disabled : False
        on_release :
            root.reconnect() 

main.py

from kivy.lang import Builder
from kivy.app import App
import socket
from kivy.uix.screenmanager import ScreenManager, Screen
from client import *
from threading import Thread

class WindowManager(ScreenManager):
    pass

class TitleWindow(Screen):  # connection to server may start here
    def __init__(self, **kwargs):
        super(TitleWindow, self).__init__(**kwargs)
        self.sock = None
        self.text = 0
        self.send_text = 0

    def next_screen(self):
        self.manager.current = "main"
        self.manager.transition.direction = "up"

    def connection(self):
        try:
            self.sock = MySocket()
            print(self.sock)
            Thread(target=self.send_data).start()
            Thread(target=self.get_data).start()
            self.manager.current = "main"
            self.manager.transition.direction = "left"
        except Exception as e:
            print(str(e))
            sleep(0.1)
            self.manager.current = "connect"
            self.manager.transition.direction = "left"

    def get_data(self):
        while True:
                self.text = self.sock.get_data()
                print(self.text.decode('utf-8'))
                return self.text
          

    def send_data(self, msg=None):
        while True:
                # msg = input()
                self.sock.send_data(msg)
                break

control = TitleWindow()

class ConnectionWindow(Screen):  # establish connection Here if not then have a button to retry

    def reconnect(self):
        try:
            control.connection()
        except WindowsError:
            print("No Connection")

    def top(self):
        self.manager.current = "title"
        self.manager.transition.direction = "up"

    pass
class MainWindow(Screen):
    def __init__(self, **kwargs):
        super(MainWindow, self).__init__(**kwargs)
        self.seat = 0

    def data_call(self):
        control.send_data = 2 
        control.send_data(str(self.seat))   #Error Occured Here     




class MyMainApp(App):
    def build(self):
        if platform == 'android' or platform == 'ios':
            Window.maximize()
        else:
            Window.size = (620, 1024)
        return WindowManager()


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    MyMainApp().run()

This is the error that I got when trying to call the "data_call" function from the MainWindow class.

self.sock.send_data(msg)
AttributeError: 'NoneType' object has no attribute 'send_data'


Solution

  • The problem is your code:

    control = TitleWindow()
    

    which creates a new instance of TitleWindow (not the one that had its connection() method called). You need to use the correct instance of TitleWindow in your MainWindow. That can be done inside the MainWindow class using something like:

    control = self.manager.get_screen('title')