Python socket Recv 无法正常工作,有人可以解释一下吗
Posted
技术标签:
【中文标题】Python socket Recv 无法正常工作,有人可以解释一下吗【英文标题】:Python socket Recv not working properly could someone explain 【发布时间】:2011-10-19 20:36:52 【问题描述】:我正在尝试为我的命令行服务器创建一个 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 "---------------------------------"
【问题讨论】:
您的原始帖子中有错字吗?self.data = s.recv(1024)
会使下一行 self.data()
看起来是个坏主意。套接字上的 recv
方法不返回可调用对象,afaik。
stonemetal 的回答是正确的。如果你对一个套接字进行两次send()
调用,每个调用都有一个 20 字节的字符串(例如文件名),recv()
ing 端可能会在单个 recv()
中获得 40 个字节,或者它可能会在一个上获得 39 个字节recv()
和下一个字节,或者可能必须调用 40 次,每次传递一个字节。您可以保证的是,它最终会非常努力地交付,并且永远不会交付任何乱序的东西。
【参考方案1】:
您在第一部分中遇到的问题是套接字是基于流而不是基于消息的。您需要提出一个消息抽象层来覆盖流。这样,管道的另一端就知道发生了什么(作为一个命令的一部分期望有多少数据),而不是猜测应该发生什么。
【讨论】:
嗨,我现在明白你的意思了,我认为尝试编写自己的协议会是一个有趣的测试。我会尝试按照 ms4py 的建议实现 struct 模块【参考方案2】:使用抽象层(Pyro、XML-RPC、zeromq)或定义您自己的协议来区分消息。
例如,作为自己的协议,您可以在每个字符串之前将消息的长度作为“标头”发送。在这种情况下,您应该使用struct
模块将长度解析为二进制格式。再次询问,如果您想采用这种方式,但我强烈建议选择上述抽象层之一。
【讨论】:
【参考方案3】:您的代码存在不同的问题。
让我们从一些人已经评论过的基础开始,send() 和 recv() 之间没有关系,你无法控制在 recv(call) 上返回的数据的哪一部分,你需要某种协议,在您的情况下,它可能就像用“\n”终止命令字符串一样简单,并在服务器上检查“\n”以使用数据。
现在其他问题:
您在使用 send 时未检查其返回大小,send() 并不能保证数据已完全写入,如果您需要,请使用 sendall()。 通过在阻塞套接字中使用 recv(1024)(默认),您的服务器代码可能会等待 1024 字节接收,这将不允许您在获得完整块之前处理消息,您需要使用非阻塞套接字和选择模块。【讨论】:
【参考方案4】:我的源代码:
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
这些函数的用法:
# 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]))
另请参阅有关recv_into(...)
、https://docs.python.org/2/library/socket.html#socket.socket.recv_into 的官方文档
【讨论】:
以上是关于Python socket Recv 无法正常工作,有人可以解释一下吗的主要内容,如果未能解决你的问题,请参考以下文章
linux epoll socket recv 不能获取正确的数据
python3.6:socket.recv() 与 socket.recv_into() 性能对比