python TCP通信线程,延迟和错误

时间:2017-01-07 17:03:10

标签: python multithreading sockets tcp

我想问你一个关于我在编码时发现的问题的问题,以提高我在TCP通信方面的技能。基本上我首先了解socket以及如何打开服务器/客户端套接字和通信。所以我为服务器编写了一个类,为客户端编写了一个类,我测试了它,我发现它们对我所关心的工作非常好:这是服务器

class server_class:
    def __init__(self, sock=None):
        if sock is None:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        else:
            self.sock = sock
    def bind(self,host, port):
        self.sock.bind((host, port))
    def listen(self,client):
        self.sock.listen(client)
    def close_client(self):
        self.client.close()
    def accept(self):
        self.client,self.c_addr=self.sock.accept()
    def invia(self,MSGLEN,msg):
        totalsent = 0
        if(len(msg)<MSGLEN):
            while(len(msg)<MSGLEN):
                msg=msg+'*'
        while totalsent < MSGLEN:
            sent = self.client.send(msg[totalsent:].encode('ascii'))
            if sent == 0:
                raise RuntimeError
            totalsent = totalsent + sent
    def ricevi(self,MSGLEN):
        msg = ''
        while len(msg) < MSGLEN:
            chunk = self.client.recv(MSGLEN-len(msg)).decode('ascii')
            if chunk == '':
                raise RuntimeError
            msg = msg + chunk
        i=0
        messaggio=''
        while(i<MSGLEN):
            if(msg[i]!='*'):
                    mess=msg[i]
                    messaggio=messaggio+mess

            else:
                    pass
            i+=1
        return messaggio

这是客户:

class client_class:
    def __init__(self, sock=None):
        if sock is None:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        else:
            self.sock = sock
    def connect(self,host,port):
        self.sock.connect((host, port))

    def invia(self,MSGLEN,msg):
        totalsent = 0
        if(len(msg)<MSGLEN):
            while(len(msg)<MSGLEN):
                msg=msg+'*'
        while totalsent < MSGLEN:
            sent = self.sock.send(msg[totalsent:].encode('ascii'))
            if sent == 0:
                raise RuntimeError
            totalsent = totalsent + sent
    def ricevi(self,MSGLEN):
        msg = ''
        while len(msg) < MSGLEN:
            chunk = self.sock.recv(MSGLEN-len(msg)).decode('ascii')
            if chunk == '':
                raise RuntimeError
            msg = msg + chunk
        i=0
        messaggio=''
        while(i<MSGLEN):
            if(msg[i]!='*'):
                    mess=msg[i]
            else:
                    pass
            messaggio=messaggio+mess
            i+=1
        return messaggio

此时没有任何问题。我尝试做的下一步是编写一个程序,在执行某些数学或GUI或两者时,保持服务器开启,以便与客户端通信,例如,它在数学中处理的信息。我发现这样做的唯一方法是使用线程模块。 我写了2个函数,一个用于服务器,一个用于数学(在while循环中增加x值)并在main中添加一个GUI。然后我将每个函数传递给一个线程。 这是服务器功能(使用之前定义的服务器类):

def server():

global Stop,x
server=server_class()
ip='192.168.1.134'
port=8033
server.bind(ip,port)
Stop=True
client=0
c_addr=0

while(Stop):
    server.listen(1)
    print("* inizio ascolto su",ip,":",port)
    server.accept()
    print("* mi sono connesso con",server.c_addr[0],":",server.c_addr[1])
    while(Stop):
            data=server.ricevi(100)
            print(data)

            if(data=="disconnetti"):
                msg="bye bye"
                server.invia(100,msg)
                server.close_client()
                print("*disconnetto il client")
                break

            if(data=="inviami x"):
                 msg=str(x)
                 server.invia(100,msg)

            if(data=="chiudi server"):
                print("*chiudo server")
                server.close_client()
                Stop=False
            else:
                 msg="come?"
                 server.invia(100,msg)

这是名为'go'的数学函数:

def go():
global x
while(x<10000):
    x+=1
    time.sleep(1)

最后主要功能是:

finestra=Tk()
finestra.geometry('800x800+300+300')
finestra.title('Prova threading')
testo_0=Label(finestra,text="Valore attuale:").grid(sticky=W,row=0,column=0)
gobutton=Button(finestra,text='Acquisisci',command=lambda: leggi())
gobutton.grid(row=2, column=1)

goo=threading.Thread(target=go)
serv=threading.Thread(target=server)
goo.start()
serv.start()
finestra.mainloop()

所以go函数连续增加x值,服务器函数保持服务器监听,主线程保持GUI,用户可以通过按下按钮看到x值。 服务器只知道来自客户端的3个命令: 1)将x传递给客户端 2)关闭客户 3)关闭服务器 对于其他消息,它作为未知命令回答。 发生的事情是沟通不好;例如,当从客户端(使用之前定义的客户端类在其他机器上运行)请求服务器传递x值(该函数不断增加)发生2个错误的事情: 1)在第一次通信之后,其他似乎延迟了,例如第二次我问x值服务器应答为未知命令,第三次我发送x值请求它给我一个值。下一次它的回答是未知的,然后给我一个值,等等。 2)在第一次通信之后,服务器传递给客户端的值被延迟,例如,如果同时我发送到服务器请求x并在GUI中按下读取x值的botton,这些将是明显的不同。

这是我使用的客户端脚本:

import time
import socket


class client_class:
    def __init__(self, sock=None):
        if sock is None:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        else:
            self.sock = sock
    def connect(self,host,port):
        self.sock.connect((host, port))

    def invia(self,MSGLEN,msg):
        totalsent = 0
        if(len(msg)<MSGLEN):
            while(len(msg)<MSGLEN):
                msg=msg+'*'
        while totalsent < MSGLEN:
            sent = self.sock.send(msg[totalsent:].encode('ascii'))
            if sent == 0:
                raise RuntimeError
            totalsent = totalsent + sent
    def ricevi(self,MSGLEN):
        msg = ''
        while len(msg) < MSGLEN:
            chunk = self.sock.recv(MSGLEN-len(msg)).decode('ascii')
            if chunk == '':
                raise RuntimeError
            msg = msg + chunk
        i=0
        messaggio=''
        while(i<MSGLEN):
            if(msg[i]!='*'):
                    mess=msg[i]
            else:
                    pass
            messaggio=messaggio+mess
            i+=1
        return messaggio


client=mysocket()
ip='192.168.1.134'
port=8033
client.connect(ip,port)


while(True):
    print("inserire comando da inviare (max 100 Bytes)")
    msg=input().encode('ascii')
    client.invia(100,msg)
    print(client.ricevi(100).decode('ascii'))

任何帮助都将不胜感激,非常感谢,抱歉英语不好

1 个答案:

答案 0 :(得分:0)

更新

我发现如果我在每次通信时关闭套接字,那么每次我需要发送消息我打开一个客户端套接字并在发送后关闭它,可以解决问题,没有错误,没有延迟。 无法解释为什么,所以如果有人能回答,我们将不胜感激。 非常感谢你