【问题标题】:How connect my Kivy client to a server (TCP, Sockets)如何将我的 Kivy 客户端连接到服务器(TCP、套接字)
【发布时间】:2018-05-24 04:58:54
【问题描述】:

因此,作为我的项目(2D 多人纸牌游戏)的一部分,我想出了如何在线托管和运行服务器脚本。我的计划是让两个单独的 kivy 客户端连接到服务器(这将只是一个带有命令的脚本)。

但是我对操作顺序有些困惑,因为我认为客户端连接可能与消息循环发生冲突,所以我想知道是否有人可以基本上告诉我我应该是什么正在做:

我将把它用作我的服务器脚本:

import socket

serversocket = socket.socket()

host = 'INSERTIPHERE'
port = PORTHERE


serversocket.bind(('', port))

serversocket.listen(1)

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

    msg = 'Thank you for connecting' + "\r\n"
    clientsocket.send(msg.encode('ascii'))
    clientsocket.close()

这是我的客户端连接函数

def Main():
    host = 'INSERTIPHERE'
    port = PORTHERE

   mySocket = socket.socket()
   mySocket.connect((host, port))

   message = input(' -> ')

   while message != 'q':
           mySocket.send(message.encode())
           data = mySocket.recv(1024).decode()
           print('Received from server: ' + data)
           message = input(' -> ')

  mySocket.close()

注意:我知道服务器和客户端在功能上并不完全一致,但如果我现在至少可以确认连接,我可以从那里开始工作。

我基本上想知道如何将这段代码放入这样的简单 kivy 应用程序中:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class BoxWidget(BoxLayout):
    pass

class BoxApp(App):

     def build(self):
        return BoxWidget()

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

我最好的猜测是你想要:

  • 在打开客户端之前建立连接
  • 在您运行客户端实例(即 BoxApp(server).run()?)时,将服务器连接传递给主要小部件(在本例中为 Box 小部件)
  • 在 BoxWidget 的消息循环函数中使用该连接

我也知道 Kivy 已经内置了 Twisted 解决方案,但我在 python 2-3 差异方面遇到了麻烦。

感谢您的阅读。

澄清一下:我现在要做的就是打开一个空白窗口,并向命令行发送一条确认消息(或在窗口中显示标签失败)。

【问题讨论】:

    标签: python-3.x sockets tcp kivy


    【解决方案1】:

    您可以使用线程,这样您就不会中断 kivy 中的主线程。
    我稍微重写了您的示例,因此您从服务器发送的内容将是标签的文本。

    server.py

    import socket
    
    
    serversocket = socket.socket()
    
    host = 'localhost'
    port = 54545
    
    
    serversocket.bind(('', port))
    
    serversocket.listen(1)
    
    clientsocket,addr = serversocket.accept()
    print("got a connection from %s" % str(addr))
    
    while True:
        msg = input("> ") + "\r\n"
        clientsocket.send(msg.encode('ascii'))
    

    client.py

    import socket
    
    class MySocket:
    
        def __init__(self,host="localhost",port=54545):
    
            self.sock = socket.socket()
            self.sock.connect((host, port))
    
    
        def get_data(self):
            return self.sock.recv(1024)
    

    main.py

    from kivy.app import App
    from kivy.uix.label import Label
    from client import *
    from threading import Thread
    
    
    class MyLabel(Label):
    
        def __init__(self, **kwargs):
            super(MyLabel,self).__init__(**kwargs)
    
            self.sock = MySocket()
            Thread(target=self.get_data).start()
    
        def get_data(self):
            while True:
                self.text = self.sock.get_data()
    
    
    class BoxApp(App):
    
         def build(self):
            return MyLabel()
    
    
    if __name__ == '__main__':
         BoxApp().run()
    

    现在只需在一个终端运行 server.py,然后从另一个终端运行 main.py

    【讨论】:

    • 谢谢你。我实际上已经设法自己找到了一个有效的非线程解决方案,使用按钮来触发定义和发送消息。 (虽然不够整洁)但是无论如何,我们都非常感谢这种帮助。
    【解决方案2】:

    我有一个使用按钮的基本版本。无论是在本地机器上还是在线上。由于必须启动回复,因此该解决方案可能不适用于许多实时应用程序甚至聊天服务器。但是,对于我的多人纸牌游戏目标来说,只要有适当的条件就足够了。

    video of test on local machine

    编辑:在视频中,我谈到了双击。我刚刚意识到这是因为第一次单击使窗口重新成为焦点。

    编辑 2:在 kv 文件中使用 TextInput 而不是 Python 文件中的输入。

    服务器脚本:

    import socket
    
    def Main():
        host = '127.0.0.1'
        port = 7000
    
        mySocket = socket.socket()
        mySocket.bind((host,port))
    
        mySocket.listen(1)
        conn, addr = mySocket.accept()
        print ("Connection from: " + str(addr))
        message = 'Thank you connecting'
        conn.send(message.encode())
    
        while True:
            data = conn.recv(1024).decode()
            strdata = str(data)
            print(strdata)
            reply = 'confirmed'
            conn.send(reply.encode())
    
        mySocket.close()
    
    if __name__ == '__main__':
        Main()
    

    这是一个非常简单的服务器。监听单个客户端,确认连接,打开发送和接收消息循环。

    这是一个并不复杂的客户端脚本:

    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.properties import ObjectProperty
    import socket
    
    class BoxWidget(BoxLayout):
        s = socket.socket()
        host = '127.0.0.1'
        port = 7000
        display = ObjectProperty()
    
    
        def connect_to_server(self):
            # called by a Button press
    
            # Connects to the server
            self.s.connect((self.host, self.port)) 
    
            # Receives confirmation from Server
            data = self.s.recv(1024).decode()      
    
            # Converts confirmation to string
            strdata = str(data)                     
    
            # Prints confirmation
            print(strdata)                                   
    
        def send_message(self):    
            # Is called by the function below
            # Encodes and sends the message variable                  
            self.s.send(self.message.encode()) 
    
            # Waits for a reply   
            self.receive_message()                     
    
        def message_to_send(self):  
            # Defines Message to send                 
            self.message = self.display.text
            # Calls function to send the message                
            self.send_message()     
    
        # Note
        # When I used message = input directly in send_message,
        # the app would crash. So I defined message input 
        # in its own function which then calls the 
        # send function  
    
        # message_to_send is the function actually
        # called by a button press which then
        # starts the chain of events
        # Define Message, Send Message, get Reply
    
        def receive_message(self):
            # Decodes a reply                    
             reply = self.s.recv(1024).decode()
    
            # Converts reply to a str
            strreply = str(reply)
    
            # prints reply
            print(strreply)
    
    class ServerApp(App):    
         def build(self):
              box = BoxWidget()
              return box
    
    if __name__ == '__main__':
        ServerApp().run()    
    

    编辑:忘记包含 kv 文件

    <BoxWidget>:
         display: display
         Button:
            text: 'Hello'
            on_press: root.message_to_send()
        Button:
            text: 'Connect'
            on_press: root.connect_to_server()
        TextInput:
            id: display
    

    在未来的迭代中,我将用条件语句替换打印语句(即客户端 1 是否抽了牌?如果是,客户端 2 的对手抽了一张面朝下的牌等)。

    现在相对初级,但您可以从这里做很多事情。

    【讨论】:

    • 这是非常糟糕的做法。您必须为客户端输入添加文本输入,而不是在您的 kivy 应用程序代码中使用输入
    • @SPSP 您说的非常正确(而且这可能不是我唯一可以解决的问题)。我已经编辑了上面的代码,所以这就是发生的事情,以及更新的视频。谢谢你的批评。
    • 你也可以通过使用线程而不是按钮来使事情更加自动化
    猜你喜欢
    • 2015-10-04
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 1970-01-01
    • 2019-09-12
    相关资源
    最近更新 更多