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

How to establish a 2 way communication using sockets in Python?

所以,我有一个服务器脚本,它从客户端脚本接收图像,并应该发送一个确认 "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")) ,客户端会收到消息。但是如果如代码所示在服务器端进行接收(图像文件)和确认的组合,则服务器端无法响应。

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

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

请帮忙。 谢谢。

这里

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

它在收到消息后循环返回等待消息,因为您在接收数据后没有中断 while 循环。 if not data: 不做任何事情,因为 recv() 停止并等待它收到消息,因此 data 永远不会什么都没有。您应该在收到消息后通过在 f.write(data) 之后添加 break 来打破循环,或者在循环中发送 OK。

嗯...我不认为我完全相信你对行为的描述。但我知道哪里出了问题。您的服务器处于接收循环中是完全合理的,因为客户端尚未向连接发出 EOF 信号。在什么情况下你认为这实际上会 break?

if not data:
    break

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

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

现在服务器下次调用 recv 时,它会返回一个空字符串,上面的 break 将被采用。

这使连接在一个方向上打开,但在另一个方向上不打开。因此客户端将无法发送更多数据。但是,在 it 关闭套接字(或使用 shutdown 本身)之前,服务器仍然能够发送给客户端。

还有一个更微妙的问题。您假设您的第一个 server-side recv 将只接收包含您的文件名的字节。 99.9% 的时间都可以。但是当服务器第一次调用 recv 时,来自下一个 client-side send 的数据可能 可用。这可能会给您一个伪造的文件名(虽然不一定是非法文件名)并且肯定意味着您的文件没有如实传输。

您永远不应该假设一个对等方的单个 send 提供的数据将被另一侧相应的单个 recv 接收。接收到的数据可能或多或少,这取决于应用程序来构建数据以确保它接收到准确的数量。