如何在Python中使用套接字建立双向通信?

时间:2018-03-02 18:20:49

标签: python-3.x sockets client-server google-compute-engine python-sockets

所以,我有一个服务器脚本从客户端脚本接收图像,并且应该发送一个“OK”的确认。但承认永远不会通过。

服务器脚本 -

import socket,sys               

s = socket.socket()         
print("Socket successfully created")

port =80                

s.bind(('', port))        
print("socket binded to %s" %(port))
s.listen(5)     
print("socket is listening")            

while True:
   c, addr = s.accept()     
   print('Got connection from', addr)
   file_name=s.recv(1024)
   file_name=fil_ename.decode("utf-8")
   with open(file_name,"wb")as f:
      while True:
         data=c.recv(1024)
         if not data:
            break
         f.write(data)

   c.send(bytes('Thank you ! File received.',"utf-8"))
   c.close()

客户端脚本 -

import socket            

s = socket.socket()         

# Define the port on which you want to connect
port = 80              

s.connect(('IP address of my server', port))
s.send(bytes("hand.jpeg","utf-8"))
f=open("back.jpeg","rb")
data=f.read(512)
while data:
    s.send(data)
    data=f.read(512)
f.close()
print(s.recv(10))

服务器不发送任何确认,似乎卡在for循环中。但是,如果我从服务器脚本中删除行c.send(bytes('Thank you ! File received.',"utf-8")),代码运行良好。此外,如果我从服务器端删除接收部分并只发送确认部分,即c.send(bytes('Thank you ! File received.',"utf-8")),则客户端会收到该消息。但如果在服务器端进行了receive(图像文件)和确认的组合,如代码所示,则服务器端无法响应。

需要注意的重要一点是,在KeyBoardInterrupting上面的程序中,它显示服务器端脚本被挂起/卡在data=c.recv(1024)行。但是如果删除确认行,同样的问题就会消失。

注意: - 客户端脚本在我的本地计算机上运行,​​服务器端脚本在Google云虚拟机实例上运行。

请帮忙。 谢谢。

2 个答案:

答案 0 :(得分:0)

这里

while True:
    data=c.recv(1024)
    if not data:
       break
    f.write(data)

它会在收到消息后循环回等待消息,因为您在接收数据后不会中断while循环。自if not data:停止后,recv()不执行任何操作,并等待收到消息,因此data永远不会发生任何事情。您应该在收到消息后通过在break之后添加f.write(data)来中断循环,或者在循环中发送OK。

答案 1 :(得分:0)

嗯......我不认为我完全相信你对这种行为的描述。但我确实知道什么是错的。您的服务器位于接收循环中是完全合理的,因为客户端没有向连接发出EOF信号。在什么情况下你认为这实际上会break

if not data:
    break

答案是客户端需要close套接字,或使用shutdown(SHUT_WR)表示它不会再发送任何数据。所以,在客户端做你想做的事:

...
f.close()
s.shutdown(socket.SHUT_WR)
...

现在,下次服务器调用recv时,它将返回一个空字符串,并且上面会显示break

这使得连接在一个方向上打开而在另一个方向上打开。因此客户端将无法再发送任何数据。但是,服务器仍然可以发送到客户端,直到关闭套接字(或使用shutdown本身)。

还有另一个更微妙的问题。您假设您的第一个服务器端recv将仅接收包含您的文件名的字节。 99.9%的时间可行。但是,当服务器第一次调用send时,您的下一个客户端recv的数据 的数据也可能。这可能会给你一个虚假的文件名(虽然不一定是非法的)并且肯定意味着你的文件没有忠实地转移。

您绝不应该假设一个对等方提供的单个send提供的数据将由另一方的相应单个recv接收。收到的数据可能或多或少,并且由应用程序决定数据的框架,以确保它准确地收到预期的数量。