如何将我的Kivy客户端连接到服务器(TCP,套接字)

时间:2017-12-10 14:41:42

标签: python-3.x sockets tcp kivy

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

然而,我对操作的顺序感到有些困惑,因为我认为客户端连接可能与消息循环冲突,所以我想知道是否有人能告诉我我该做什么:

我将使用它作为我的serverscript:

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(服务器).run()时)将服务器连接传递给主窗口小部件(在本例中为Box Widget)?)
  • 在BoxWidget的消息循环函数中使用该连接

我也明白Kivy已经内置了Twisted的解决方案,但是我遇到了python 2-3差异的问题。

感谢您的阅读。

只是为了澄清:我现在想要做的就是打开一个空白窗口,并且还有一条确认消息发送到命令行(或者在窗口中没有标签)。

2 个答案:

答案 0 :(得分:0)

您可以使用线程,这样就不会在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

答案 1 :(得分:0)

我有一个使用按钮的基本版本。在本地机器和在线。由于必须启动回复,因此对于许多实时应用甚至聊天服务器而言,此解决方案可能不可行。然而,对于我的多人纸牌游戏的目标,它应该足以满足条件。

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

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

现在相对简陋,但你可以从这里做很多事情。