Python套接字Recv工作不正常,有人能解释一下吗

Python套接字Recv工作不正常,有人能解释一下吗,python,sockets,Python,Sockets,我正在尝试为我的命令行服务器创建gui客户端。然而,我遇到了一些恼人的问题,我似乎无法解决 我不是100%确定实际的问题是什么,因为有时代码会工作,而有时它不会。我想主要的问题是我最初试过 while 1: self.data = s.recv(1024) if not self.data(): break else: print self.data() 然后我就把这个发过去了 for f in files: s.

我正在尝试为我的命令行服务器创建gui客户端。然而,我遇到了一些恼人的问题,我似乎无法解决

我不是100%确定实际的问题是什么,因为有时代码会工作,而有时它不会。我想主要的问题是我最初试过

while 1:
    self.data = s.recv(1024)
    if not self.data():
          break
    else:
          print self.data()
然后我就把这个发过去了

  for f in files:
      s.send(f)
每个f都是一个文件名字符串。我希望它会出现在recv端,因为每次recv调用都会收到一个文件名,但是在一次recv调用中,我得到了一大块文件名,我认为值1024个字符

这使得无法检查数据的结尾,因此循环从未退出

这就是我现在的代码

def get_data(self,size = 1024):

    self.alldata = ""
    while 1:

        while gtk.events_pending():
             gtk.main_iteration()

        self.recvdata = self.s.recv(size)
        self.alldata += self.recvdata
        if self.alldata.find("\r\n\r\nEOF"):
           print "recieved end message"
           self.rdata = self.alldata[:self.alldata.find("\r\n\r\nEOF")]
           break



    print "All data Recieved: " + str(len(self.rdata)) + "Bytes"
    print "All data :\n" + self.rdata + "\n-------------------------------------------------"  

    self.infiles = self.rdata.split("-EOS-")
    for nf in self.infiles:
        if len(nf) > 2:
            self.add_message(self.incomingIcon,nf)
在那一刻,我正试图让客户端正确地从服务器读取数据。我希望发生的是,当输入命令列表并将其发送到客户端时,服务器会发回数据,并且每个文件都会附加到列表存储中

有些时候这一切正常,其他时候只有1200个文件中的一个被返回,如果它执行正常,如果我尝试键入另一个命令并发送它,整个gtk窗口就会关闭,程序变得没有响应

对不起,我不能更好地解释这个问题,我尝试了很多不同的解决方案,所有这些都会产生不同的错误

如果有人能解释recv命令以及它为什么会出现错误,这就是我向客户端发送数据的方式

if(commands[0] == 'list'):
    whatpacketshouldlooklike=""
    print "[Request] List files ", address
    fil = list_files(path)
    for f in fil:
         sdata =  f  
         whatpacketshouldlooklike += sdata + "-EOS-"
         newSock.send(sdata +"-EOS-")
         #print "sent: " + sdata
         newSock.send("\r\n\r\nEOF")
    whatpacketshouldlooklike += "\r\n\r\nEOF"
    print "---------------------------------"
    print whatpacketshouldlooklike
    print "---------------------------------"

您在第一部分中遇到的问题是套接字是基于流的,而不是基于消息的。您需要提出一个消息抽象,以便在流的顶部分层。这样,管道的另一端知道发生了什么(作为一个命令的一部分,需要多少数据),而不是猜测应该发生什么。

使用抽象层(,)或定义自己的协议来区分消息


例如,作为自己的协议,您可以在每个字符串之前将消息的长度作为“头”发送。在这种情况下,您应该使用
struct
模块将长度解析为二进制格式。如果您想这样做,请再次询问,但我强烈建议您选择上述抽象层之一。

您的代码存在不同的问题

让我们从一些人已经评论过的基本问题开始,sends()和recv()之间没有关系,您无法控制recv(调用)返回的数据的哪一部分,您需要某种协议,在您的情况下,它可以像用“\n”终止命令字符串并检查“\n”一样简单在服务器上使用数据

现在还有其他问题:

  • 使用send时未检查其返回大小,send()不能保证数据已完全写入,如果需要,请使用sendall()
  • 通过在阻塞套接字(默认)中使用recv(1024),您的服务器代码可能会等待接收1024个字节,这将不允许您处理消息,直到您获得完整的块,您需要使用非阻塞套接字和选择模块
我的源代码:

def readReliably(s,n):
    buf = bytearray(n)
    view = memoryview(buf)
    sz = 0
    while sz < n:
        k = s.recv_into(view[sz:],n-sz)
        sz += k
    # print 'readReliably()',sz
    return sz,buf

def writeReliably(s,buf,n):
    sz = 0
    while sz < n:
        k = s.send(buf[sz:],n-sz)
        sz += k
    # obj = s.makefile(mode='w')
    # obj.flush()
    # print 'writeReliably()',sz
    return sz

另请参见关于
recv_进入(…)

您的原始帖子中是否有打字错误
self.data=s.recv(1024)
会让下一行
self.data()
看起来像个坏主意。socket上的
recv
方法不会返回可调用对象。如果您对套接字进行两次
send()
调用,每次调用一个20字节的字符串(例如文件名),
recv()
ing端可能在单个
recv()
中获得40个字节,或者可能在一个
recv()
上获得39个字节,在下一个
recv()
上获得1个字节,或者可能需要调用40次,每次传递一个字节。你所能保证的是,它最终会非常努力地交付,并且永远不会交付任何不正常的东西。嗨,我现在明白你的意思了,我认为尝试编写我自己的协议将是一个有趣的测试。我会按照ms4py的建议尝试实现结构模块
# Server
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
s.bind((host,port))
s.listen(10) # unaccepted connections
while True:
  sk,skfrom = s.accept()
  sz,buf = io.readReliably(sk,4)
  a = struct.unpack("4B",buf)
  print repr(a)
  # ...
  io.writeReliably(sk,struct.pack("4B",*[0x01,0x02,0x03,0x04]))