我目前有一个在此代码下运行的服务器:
import socket
port = 60000
s = socket.socket()
host = socket.gethostname()
s.bind((host, port))
s.listen(1)
print ('Server listening....')
while True:
conn, addr = s.accept()
print ('Got connection from', addr)
data = conn.recv(1024)
print('Server received', repr(data))
filename='mytext.txt'
f = open(filename,'rb')
l = f.read(1024)
while (l):
conn.send(l)
print('Sent ',repr(l))
l = f.read(1024)
f.close()
print('Done sending')
conn.send('Thank you for connecting')
conn.close()
在此代码下运行的客户端:
import socket
s = socket.socket()
host = socket.gethostname()
port = 60000
s.connect((host, port))
s.send('Test')
with open('received_file', 'wb') as f:
print ('file opened')
while True:
print('receiving data...')
data = s.recv(1024)
print('data=%s', (data))
if not data:
break
# write data to a file
f.write(data)
f.close()
print('Successfully get the file')
s.close()
print('connection closed')
问题在于,当客户端尝试发送数据时,它表示发送的数据必须是字节类型的对象(此处显示错误代码:https://gyazo.com/97ef155f6809a801b02f381670895a2b。)我在互联网上搜索了答案如何在Python 3中创建一个字节类型对象,但我找不到任何有用的东西。
答案 0 :(得分:2)
如果您只是发送文字,则可以使用bytes
文字而不是str
字面值,前缀为b
。而不是:
sock.send('Hello')
......就这样做:
sock.send(b'Hello')
如果您要发送字符串变量,则需要encode
发送字符串变量,并在接收时可能decode
。而不是:
sock.send(msg)
resp = sock.recv(4096)
......做:
sock.send(msg.encode('ascii')
resp = sock.recv(4096).decode('ascii')
如果要发送非ASCII字符串,则需要选择编码。除非你有充分的理由不这样做,否则请使用UTF-8。
要记住的另一件事是:TCP套接字只是字节流,而不是消息,它们可以任意拆分成数据包。如果可以recv(1024)
,则可能只会获得对方通过send
发送的内容的一部分。如果您发送的字符串长度超过1024字节,那可能很明显,但即使是较短的字符串,也可能发生。或者,如果您没有严格交替发送和接收,您可以将多个发送连接到单个接收。如果您发送hello
然后world
并将其作为helloworld
接收,则无法知道发生了什么,或者如何将其拆分回来。
而且,更糟糕的是,当您在闲置计算机上测试localhost时,它可能不会发生,因此在开发过程中看起来会很好看,但是一旦你在整个地方都会神秘地失败把它部署到某个地方。
因此,您需要一些描述一条消息结束而另一条消息开始的协议。我有a blog post解释了一些选项,并展示了如何实现它们。
但是,如果您只是将人类可读的字符串作为消息发送,并且这些字符串永远不会包含换行符,则最简单的协议只是每条消息的一行,就像您编写文本文件一样。并查看socket.makefile
:它为您提供的内容就像文件一样,为每个消息协议处理一行,并自动处理encode
和decode
部分。所以,而不是:
sock.send(msg.encode('utf-8'))
resp = sock.recv(1024).decode('utf-8')
...您只需使用makefile
来获取可读写的文件对象,然后执行:
wf.write(msg + '\n')
resp = next(rf)
...然后您不必担心如何缓冲接收并将其拆分为消息。
答案 1 :(得分:1)
更改客户端代码行:
s.send('Test')
为:
s.send(b'Test')
在https://docs.python.org/3/library/socket.html找到有关socket.send()的更多详细信息。