TCP客户端和服务器间传输数据遇到的TypeError: a bytes-like object is required, not 'str'问题
使用python实现python核心编程3第472页和474页的TCP时间戳服务器和客户端服务器间数据传输编程时遇到TypeError: a bytes-like object is required, not 'str'报错问题,经查找资料知道是Python中的字符串数据和字节数据在python3中不能混用所致,一博文 https://eli.thegreenplace.net/2012/01/30/the-bytesstr-dichotomy-in-python-3 对python3中字符串和字节数据间区别联系做了较详细解释。
下面是https://www.cnblogs.com/abclife/p/7445222.html 进行的译文
python 3中最重要的新特性可能就是将文本(text)和二进制数据做了更清晰的区分。文本总是用unicode进行编码,以str类型表示;而二进制数据以bytes类型表示。
在python3中,不能以任何隐式方式将str和bytes类型二者混合使用。不可以将str和bytes类型进行拼接,不能在str中搜索bytes数据(反之亦然),也不能将str作为参数传入需要bytes类型参数的函数(反之亦然)。
字符串和字节符之间划分界线是必然的。下面这个图解要牢记于心:
strings可以被编码(encode)成字bytes,bytes也可以解码(decode)成strings:
1 >>> '€20'.encode('utf-8') 2 b'\xe2\x82\xac20' 3 >>> b'\xe2\x82\xac20'.decode('utf-8') 4 '€20'
可以这样理解:
string是文本(text)的抽象表示。字符串(string)由字符组成,字符也是抽象的实体且与任何二进制表示无关。
当操纵字符串的时候,很多细节是不用了解的。我们可以分割、切片和拼接字符串,在字符串内部进行搜索。但并不在乎内部是如何表示的,也不用在意底层一个字符要花费多少byte。
只有在需要将string编码(encode)成byte的时候,比如:通过网络传输数据;或者需要将byte解码(decode)成string的时候,我们才会关注string和byte的区别。
传入encode和decode的参数是编码方式。编码是一种用二进制数据表示抽象字符的方式。目前有很多种编码。上面给出的UTF-8是其中一种,下面是另一种:
1 >>> '€20'.encode('iso-8859-15') 2 b'\xa420' 3 >>> b'\xa420'.decode('iso-8859-15') 4 '€20'
编码是这个转换过程中至关重要的一部分。若不编码,bytes对象b'\xa420'只是一堆比特位而已。编码赋予其含义。采用不同的编码,这堆比特位的含义就会大不同:
1 >>> b'\xa420'.decode('windows-1255') 2 '₪20'
因而服务器端编码
1 from socket import * 2 from time import ctime 3 4 HOST='' 5 PORT=21567 6 BUFSIZ=1024 7 ADDR=(HOST,PORT) 8 9 tcpSerSock=socket(AF_INET,SOCK_STREAM) 10 tcpSerSock.bind(ADDR) #绑定地址到套接字 11 tcpSerSock.listen(5) #开始TCP监听 12 13 while True: 14 print('waiting for connection...') 15 tcpSerSock,addr=tcpSerSock.accept()#被动接受TCP客户端连接,等待连接的到来 16 print('...connected from:',addr) 17 18 while True: 19 data=tcpSerSock.recv(BUFSIZ) 20 print(data.decode()) #服务器接受到客户端发送来的数据是字节类型,需要转换为字符串类型 21 if not data: 22 break 23 tcpSerSock.send(('[%s] %s'%(ctime(),data)).encode()) # 网络传输数据前将字符串数据转化为字节类型 24 tcpSerSock.close() 25 tcpSerSock.close()
客户端编程
1 from socket import * 2 3 HOST='localhost' 4 PORT=21567 5 BUFSIZ=1024 6 ADDR=(HOST,PORT) 7 8 tcpCliSock=socket(AF_INET,SOCK_STREAM) 9 tcpCliSock.connect(ADDR) 10 11 while True: 12 data=input('>') 13 if not data: 14 break 15 tcpCliSock.send(data.encode()) #网络传输数据前将字符串数据转化为字节类型 16 data=tcpCliSock.recv(BUFSIZ).decode() #将收到的字节类型数据转化为字符串数据 17 if not data: 18 break 19 print(data) 20 21 22 tcpCliSock.close()
客户端显示
1 >what?? 2 [Sat Mar 31 16:03:20 2018] b'what??' 3 >excuse me? 4 [Sat Mar 31 16:03:52 2018] b'excuse me?' 5 >
服务器端显示
1 waiting for connection... 2 ...connected from: ('127.0.0.1', 50782) 3 what?? 4 excuse me?
udp服务器端编程
1 from socket import * 2 from time import ctime 3 4 HOST='' 5 PORT=21567 6 BUFSIZ=1024 7 ADDR=(HOST,PORT) 8 9 udpSerSock=socket(AF_INET,SOCK_DGRAM) 10 udpSerSock.bind(ADDR) 11 12 while True: 13 print('waiting for message...') 14 data,addr=udpSerSock.recvfrom(BUFSIZ) #data是字节对象,addr是字符串对象 15 print(data) 16 print(addr) 17 data=data.decode() 18 data='[%s]%s'%(ctime(),data) 19 udpSerSock.sendto(data.encode(),addr) 20 print('..received from and returned to:',addr) 21 22 udpSerSock.close()
客户端编程
1 from socket import * 2 3 HOST='localhost' 4 PORT=21567 5 BUFSIZ=1024 6 ADDR=(HOST,PORT) 7 8 udpCliSock=socket(AF_INET,SOCK_DGRAM) 9 while True: 10 data=input('>').encode() 11 if not data: 12 break 13 udpCliSock.sendto(data,ADDR) 14 data,ADDR=udpCliSock.recvfrom(BUFSIZ) 15 if not data: 16 break 17 else: 18 print(data.decode()) 19 # print(udpCliSock.close()) 20 21 udpCliSock.close()
服务器端显示
1 waiting for message... 2 b'who is that?' 3 ('127.0.0.1', 60959) 4 ..received from and returned to: ('127.0.0.1', 60959) 5 waiting for message... 6 b'I am Jack' 7 ('127.0.0.1', 60959) 8 ..received from and returned to: ('127.0.0.1', 60959) 9 waiting for message... 10 b'sending through UDP' 11 ('127.0.0.1', 60959) 12 ..received from and returned to: ('127.0.0.1', 60959) 13 waiting for message...
客户端显示
1 >who is that? 2 [Sat Mar 31 16:47:15 2018]who is that? 3 >I am Jack 4 [Sat Mar 31 16:47:24 2018]I am Jack 5 >sending through UDP 6 [Sat Mar 31 16:47:32 2018]sending through UDP 7 >