【问题标题】:python socket programming for transferring a photo用于传输照片的python套接字编程
【发布时间】:2018-12-18 20:27:22
【问题描述】:

我是 python 中套接字编程的新手。这是一个在 Mininet 主机中打开 TCP 套接字并将照片从一台主机发送到另一台主机的示例。事实上,为了满足我的要求,我更改了用于向另一台主机 (writing the received data to a text file) 发送简单消息的代码。虽然当我实现这个修改后的代码时,没有错误并且似乎可以正确传输,但我不确定这是否是执行此传输的正确方法。由于我在同一台机器上运行两台主机,我认为它可能会对结果产生影响。我想请您检查这是否是正确的转移方式,或者我应该添加或删除某些内容。

mininetSocketTest.py #!/usr/bin/python

from mininet.topo import Topo, SingleSwitchTopo
from mininet.net import Mininet
from mininet.log import lg, info
from mininet.cli import CLI

def main():
    lg.setLogLevel('info')

    net = Mininet(SingleSwitchTopo(k=2))
    net.start()

    h1 = net.get('h1')
    p1 = h1.popen('python myClient2.py')

    h2 = net.get('h2')
    h2.cmd('python myServer2.py')

    CLI( net )
    #p1.terminate()
    net.stop()

if __name__ == '__main__':
     main()

myServer2.py

import socket
import sys

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('10.0.0.1', 12345))

buf = 1024
f = open("2.jpg",'wb')

s.listen(1)
conn , addr = s.accept()
while 1:
    data = conn.recv(buf)
    print(data[:10])
    #print "PACKAGE RECEIVED..."
    f.write(data)   
    if not data: break
    #conn.send(data)
conn.close()
s.close()

myClient2.py:

import socket
import sys

f=open ("1.jpg", "rb")
print sys.getsizeof(f)
buf = 1024
data = f.read(buf)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('10.0.0.1',12345))


while (data):
    if(s.sendall(data)):
        #print "sending ..."
        data = f.read(buf)
        print(f.tell(), data[:10])
    else:
         s.close()
s.close()

【问题讨论】:

  • “我的代码有效,请查看”可能是 Code Review 的问题,而不是 Stack Overflow 的问题。

标签: python file-transfer mininet


【解决方案1】:

首先,您应该使用 TCP 而不是 UDP。 TCP 将确保您的客户端/服务器已正确接收到整张照片。 UDP更多地用于内容流。 绝对不是您的用例。

【讨论】:

  • 是的,你是对的。然而这只是一个示例案例,如果我知道这段代码的问题是什么,使用 TCP 实现它也会容易得多:)
  • 亲爱的 Jonathan,我尝试更改我的代码,以便它可以使用 TCP 而不是 UDP。我编辑了我的代码。请您看看它现在是否正确?
  • 我认为这至少是对该问题原始版本的部分回答,但此后已对其进行了编辑,因此该问题不再存在此问题,但仍有几个其他问题。
【解决方案2】:

client2 中的这个循环是错误的:

while (data):
    if(s.send(data)):
        print "sending ..."
        data = f.read(buf)

作为send 文档说:

返回发送的字节数。应用程序负责检查所有数据是否已发送;如果仅传输了部分数据,则应用程序需要尝试传输剩余数据。有关此主题的更多信息,请咨询Socket Programming HOWTO

你甚至没有尝试这样做。因此,虽然它可能在 localhost 上运行,在负载较轻的机器上,文件较小,但一旦您尝试真正使用它,它就会崩溃。

正如帮助所说,您需要做一些事情来传递缓冲区的其余部分。由于可能没有充分的理由您不能在全部发送之前阻止,因此最简单的方法是致电sendall

与 send() 不同,此方法继续从字节发送数据,直到所有数据都已发送或发生错误。成功时不返回任何内容。出错时会引发异常……


这带来了下一个问题:您没有在任何地方进行任何异常处理。也许这没关系,但通常不是这样。例如,如果您的一个套接字出现故障,但另一个套接字仍处于打开状态,您是要中止整个程序并硬断开连接,还是要先完成发送所有内容?

您至少应该使用finallywith 子句,以确保您close 您的套接字干净,因此对方将获得一个不错的EOF 而不是异常。


另外,您的服务器代码只为单个客户端提供服务,然后退出。这真的是你想要的吗?通常,即使您不需要并发客户端,您也至少希望循环接受并为它们一一提供服务。


最后,服务器几乎总是希望这样做:

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

如果没有这个,如果您在服务器完成后的几秒钟内尝试再次运行服务器(特定于平台的秒数,这甚至可能取决于它是否以异常结束而不是完全关闭),@987654332 @ 会失败,就像你试图绑定一个实际上被另一个程序使用的套接字一样。

【讨论】:

  • 感谢您的回复。我将 send 更改为 sendall,但随后我在服务器端出现了一个无限循环,打印 PACKAGE RECEIVED...PACKAGE RECEIVED...PACKAGE RECEIVED... .... 而我的新文件 (2.jpg) 已损坏跨度>
  • 关于第三种情况,由于我只是在测试socket编程,所以我的服务器此时只接受一个客户端,但其实你是对的。它可以接受更多的客户。关于最后一种情况,我在此行之后添加了 s.setsockopt(socket.SOL_SOCKET, socket, SO_REUSEADDR, 1) : s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 但我遇到了一个错误,指出未定义 SO_REUSEADDR
  • @helen 对不起;是socket.SO_REUSEADDR,而不是socket, SO.REUSEADDR。 (这就是我在平板电脑上编辑所得到的……) 至于无限循环……如果if not data: break 从未发生过,这意味着data = conn.recv(buf) 不断返回非空缓冲区。只有当客户端永远发送时才会发生这种情况。但是客户端一直在做data = f.read(buf)直到它为空,并且您还没有打开像/dev/zero这样的无限大小的伪文件,所以这没有意义。
  • @helen: 你能编辑代码让服务器print(data[:10]) 和客户端print(f.tell(), data[:10]) 什么的吗?
  • @helen 值得注意的是,对于中等大小的 JPEG,您将收到数百甚至数千条 PACKAGE RECEIVED… 消息,因为您每 1KB 打印一次,但它终将结束。
猜你喜欢
  • 2023-03-13
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
  • 1970-01-01
  • 2018-02-28
相关资源
最近更新 更多