程序在socket交互时挂起

2 投票
2 回答
3838 浏览
提问于 2025-04-15 23:06

我有两个程序,分别是sendfile.py和recvfile.py,它们的目的是通过网络发送一个文件。这两个程序是通过TCP套接字进行通信的。它们的交流应该是这样的:

sender =====filename=====> receiver

sender <===== 'ok' ======= receiver
               or
sender <===== 'no' ======= receiver

if ok:
sender ====== file ======> receiver 

我有

发送方和接收方的代码如下:

发送方:

import sys
from jmm_sockets import *

if len(sys.argv) != 4:
    print "Usage:", sys.argv[0], "<host> <port> <filename>"
    sys.exit(1)

s = getClientSocket(sys.argv[1], int(sys.argv[2]))

try:
    f = open(sys.argv[3])
except IOError, msg:
    print "couldn't open file"
    sys.exit(1)

# send filename
s.send(sys.argv[3])

# receive 'ok'
buffer = None
response = str()
while 1:
    buffer = s.recv(1)
    if buffer == '':
        break
    else:
        response = response + buffer
if response == 'ok':
    print 'receiver acknowledged receipt of filename'
    # send file
    s.send(f.read())
elif response == 'no':
    print "receiver doesn't want the file"

# cleanup
f.close()
s.close()

接收方:

from jmm_sockets import *

s = getServerSocket(None, 16001)
conn, addr = s.accept()


buffer = None
filename = str()

# receive filename
while 1:
    buffer = conn.recv(1)
    if buffer == '':
        break
    else:
        filename = filename + buffer
print "sender wants to send", filename, "is that ok?"
user_choice = raw_input("ok/no: ")

if user_choice == 'ok':
    # send ok
    conn.send('ok')
    #receive file
    data = str()
    while 1:
        buffer = conn.recv(1)
        if buffer=='':
            break
        else:
            data = data + buffer
            print data
else:
    conn.send('no')
conn.close()

我觉得这里可能有点问题,像是出现了死锁,但我不知道具体是什么原因。

2 个回答

3

在使用阻塞套接字的情况下,这种方式是默认的,我想你可能在用这种方式(因为你用的模块 jmm_sockets 有点神秘,我不能确定)。在这种情况下,recv 方法是阻塞的——这意味着它不会在“暂时没有更多内容可以返回”的时候返回一个空字符串,正如你所想的那样。

你可以通过其他方法来解决这个问题,比如在你想发送的实际字符串后面加一个明确的结束符(这个字符在文件名中不能出现),例如 '\xff',然后在另一端等待这个字符,以此来表示所有的字符串已经接收完毕。

2

TCP是一种流式协议,它并不理解消息的边界。对于一个阻塞的套接字,recv(n) 只有在发送方关闭了套接字或者明确调用了shutdown(SHUT_WR)时,才会返回一个零长度的字符串。否则,它可能会返回一个长度在1到n字节之间的字符串,并且会一直等待,直到至少有一个字节可以返回。

你需要自己设计一种协议来判断何时接收到完整的消息。可以考虑以下几种方法:

  1. 使用固定长度的消息。
  2. 发送一个固定长度的消息,先说明总消息长度,然后再发送可变长度的部分。
  3. 发送消息后,再发送一个独特的结束消息,这个结束消息在正常消息中不会出现。

另一个你可能会遇到的问题是,send() 并不能保证发送所有的数据。返回值表示实际发送的字节数,发送方需要负责不断调用send,直到所有的消息字节都发送完毕。你也可以考虑使用sendall()方法。

撰写回答