如何通过套接字发送消息序列?

时间:2019-02-01 21:36:57

标签: python-3.x sockets

我正在尝试通过Python中的套接字进行通信。我有一个server.py文件和一个client.py。后者正在请求用户输入并将其发送到服务器。根据用户输入,服务器正在播放2种不同的声音。此操作只能运行一次,但不能再次尝试。

我已经放入了一些print(XYZ)行,以查看程序在哪里停止。发送第一条消息后,不再执行server.py的“ print(” ...“)”行。因此,看起来server_socket.accept()不再成功。为什么会这样?

这是server.py:

SDNA

这是client.py:

import socket
import winsound

fnameBeep = "beep.wav"
fnameBop = "bop.wav"

server_socket = socket.socket(socket.AF_INET,
                              socket.SOCK_STREAM)
server_addr = ("127.0.0.1", 1337)
server_socket.bind(server_addr)
server_socket.listen(1000)
while True:
    print("waiting...")
    (client_socket, addr) = server_socket.accept()
    print("...")
    msg = client_socket.recv(1024)
    print(msg)
    print("Received: " + str(msg, "utf8"))
    if str(msg, "utf8") == '1':
        winsound.PlaySound(fnameBeep, winsound.SND_FILENAME)
    else:
        winsound.PlaySound(fnameBop, winsound.SND_FILENAME)    

出了什么问题?常规通信正在运行,但是我想向服务器发送一系列消息。

1 个答案:

答案 0 :(得分:1)

你会想要做的第一件事就是将你的accept()调用上面的while循环的顶部 - 因为它是你的代码试图接受新的TCP连接在每个命令之后,我认为这不是您想要执行的操作-大概是想保持单个TCP连接打开,并通过该TCP连接接收多个命令。

第二个问题是成帧:关于TCP的要记住的事情是它实现了字节的原始流,并且自己没有对消息进行任何固定的成帧。如果在发送侧执行以下呼叫:

client_socket.send("123")
client_socket.send("456")
client_socket.send("789")

...在接收端,服务器可能会从其后续的recv()调用返回以下数据块:

recv() call #1:  12345
recv() call #2:  67
recv() call #3:  89

...或者,它可能代替(视网络是如何工作的,相月亮等)得到如下:

recv() call #1:  1
recv() call #2:  2345678
recv() call #3:  9

否则它可能会在一次调用中获得所有已发送的数据:

recv() call #1:  123456789

或者它甚至可以通过单独的调用接收每个字节:

recv() call #1:  1
recv() call #2:  2
recv() call #3:  3
recv() call #4:  4
recv() call #5:  5
recv() call #6:  6
recv() call #7:  7
recv() call #8:  8
recv() call #9:  9

...或任何其他组合你能想象的。

所以问题是,考虑到数据分块的不确定性,接收者如何才能知道您的客户端打算发送(“ file_name1.wav”然后是“ file_name2.wav”)而不是仅仅发送(“ file_name1.wavfile_name”) .wav”)或(“文件”,“ name1.wavfile ”,“ name.wav”)等?

为了清楚地解析传入的TCP字节,接收方必须知道如何对其进行成帧。对于像您这样的简单程序,框架逻辑可能很简单-例如只需声明一个规则,即每个字符串的末尾都有换行符。然后,你的服务器可以简单地保持接收字节(并将其添加到字符串的结尾),直到它看到一个换行符字节,此时它知道它已收到完整的用户命令,因此它可以在这一点上处理该命令,然后删除所有字符串(直到并包括换行符),然后继续解析下一个字符串。

另一种方法是让发送方在每个命令之前包含一个短(固定长度)标头,指示接收方在下一个命令中应该看到的字节数。然后服务器可以读取头(因为头是固定长度的,服务器就会知道它需要多少字节读取它具有完整的头前看),然后阅读,多字节,则处理命令,然后重复。