目前正在學習python基本語法以及電腦網路課,所以正好結合學習python網路編程,看的是《python核心編程》第三版,發現示例2-1代碼返回錯誤…..糾結很久 發現這裡python3.5和Python2.7在套接字返回值解碼上有區別。 先介紹一下 python bytes和str兩種類型轉換 ...
目前正在學習python基本語法以及電腦網路課,所以正好結合學習python網路編程,看的是《python核心編程》第三版,發現示例2-1代碼返回錯誤…..糾結很久
發現這裡python3.5和Python2.7在套接字返回值解碼上有區別。
先介紹一下 python bytes和str兩種類型轉換的函數encode(),decode()
- str通過encode()方法可以編碼為指定的bytes
- 反過來,如果我們從網路或磁碟上讀取了位元組流,那麼讀到的數據就是bytes。要把bytes變為str,就需要用decode()方法:
python核心編程書中的2-1例子
TCP伺服器:
#coding=utf-8
#創建TCP伺服器
from socket import *
from time import ctime
HOST=''
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcpSerSock=socket(AF_INET,SOCK_STREAM) #創伺服器套接字
tcpSerSock.bind(ADDR) #套接字與地址綁定
tcpSerSock.listen(5) #監聽連接,傳入連接請求的最大數
while True:
print('waiting for connection...')
tcpCliSock,addr =tcpSerSock.accept()
print('...connected from:',addr)
while True:
data =tcpCliSock.recv(BUFSIZ)
#print('date=',data)
if not data:
break
tcpCliSock.send(('[%s] %s' %(ctime(),data)))
tcpCliSock.close()
tcpSerSock.close()
TCP客戶端
#coding=utf-8
from socket import *
HOST = 'localhost' # or 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR=(HOST,PORT)
tcpCliSock = socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR)
while True:
data = input('> ')
print('data=',data);
if not data:
break
tcpCliSock.send(data)
data = tcpCliSock.recv(BUFSIZ)
if not data:
break
print(data)
tcpCliSock.close()
返回的錯誤提示:
TypeError: a bytes-like object is required, not ‘str’
指的是18行tcpCliSock.send(data)
傳入的參數是應該是bytes類型,而不是str類型。
於是我去百度,發現在StackOverflow上發現有人也出現同樣的問題,並一個叫Scharron的人提出瞭解答:
In python 3, bytes strings and unicodestrings are now two different types. Since sockets are not aware of string encodings, they are using raw bytes strings, that have a slightly differentinterface from unicode strings.
So, now, whenever you have a unicode stringthat you need to use as a byte string, you need toencode() it. And whenyou have a byte string, you need to decode it to use it as a regular(python 2.x) string.
Unicode strings are quotes enclosedstrings. Bytes strings are b”” enclosed strings
When you use client_socket.send(data),replace it by client_socket.send(data.encode()). When you get datausing data = client_socket.recv(512), replace it by data =client_socket.recv(512).decode()
於是我去查python3.5的幫助手冊。
socket.send(bytes[, flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data. For further information on this topic, consult the Socket Programming HOWTO.
Changed in version 3.5: If the system call is interrupted and the signal handler does not raise an exception, the method now retries the system call instead of raising an InterruptedError exception (see PEP 475 for the rationale).
socket.recv(bufsize[, flags])
Receive data from the socket. The return value is a bytes object representing the data received. The maximum amount of data to be received at once is specified by bufsize. See the Unix manual page recv(2) for the meaning of the optional argument flags; it defaults to zero.
Note
For best match with hardware and network realities, the value of bufsize should be a relatively small power of 2, for example, 4096.
Changed in version 3.5: If the system call is interrupted and the signal handler does not raise an exception, the method now retries the system call instead of raising an InterruptedError exception (see PEP 475 for the rationale).
修正後:
tcp伺服器
#coding=utf-8
#創建TCP伺服器
from socket import *
from time import ctime
HOST=''
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcpSerSock=socket(AF_INET,SOCK_STREAM) #創伺服器套接字
tcpSerSock.bind(ADDR) #套接字與地址綁定
tcpSerSock.listen(5) #監聽連接,傳入連接請求的最大數
while True:
print('waiting for connection...')
tcpCliSock,addr =tcpSerSock.accept()
print('...connected from:',addr)
while True:
data =tcpCliSock.recv(BUFSIZ).decode()
print('date=',data)
if not data:
break
tcpCliSock.send(('[%s] %s' %(ctime(),data)).encode())
tcpCliSock.close()
tcpSerSock.close()
tcp客戶端:
#coding=utf-8
from socket import *
HOST = 'localhost' # or 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR=(HOST,PORT)
tcpCliSock = socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR)
while True:
data = input('> ')
#print('data=',data);
if not data:
break
tcpCliSock.send(data.encode())
data = tcpCliSock.recv(BUFSIZ).decode()
if not data:
break
print(data)
tcpCliSock.close()
socket.sendto(bytes, address)
socket.sendto(bytes, flags, address)
Send data to the socket. The socket should not be connected to a remote socket, since the destination socket is specified by address. The optional flags argument has the same meaning as for recv() above. Return the number of bytes sent. (The format of address depends on the address family — see above.)
Changed in version 3.5: If the system call is interrupted and the signal handler does not raise an exception, the method now retries the system call instead of raising an InterruptedError exception (see PEP 475 for the rationale).
socket.recvfrom(bufsize[, flags])
Receive data from the socket. The return value is a pair (bytes, address) where bytes is a bytes object representing the data received and address is the address of the socket sending the data. See the Unix manual page recv(2) for the meaning of the optional argument flags; it defaults to zero. (The format of address depends on the address family — see above.)
同理修正udp伺服器:
from socket import *
from time import ctime
HOST=''
PORT=21546
BUFSIZ=1024
ADDR=(HOST,PORT)
udpSerSock = socket(AF_INET,SOCK_DGRAM)
udpSerSock.bind(ADDR)
while True:
print('waiting for message...')
data,addr=udpSerSock.recvfrom(BUFSIZ)
data=data.decode()
udpSerSock.sendto(('[%s] %s'%(ctime(),data)).encode(),addr)
print('...received from and returned to:',addr)
udpSerSock.close()
原博:http://blog.csdn.net/yexiaohhjk/article/details/68066843