版权声明:转载请注明出处 https://blog.csdn.net/weixin_39653948/article/details/82986258
《Python 核心编程》第三版书中的代码在实际应用过程中,由于版本更迭,已经或多或少出现了错误,因此在本博客中记录一下报错的解决过程,并记录学习过程中的笔记。
书中第二章 网络编程 Python 3.6 报错:
tcpCliSock.send(data)
TypeError: a bytes-like object is required, not ‘str’
以下为正确代码:
1.TCP(传输控制协议):
服务器端:
'''
本脚本创建一个TCP服务器,它接受来自客户端的消息,然后将消息加上时间戳前缀并发送回客户端。
'''
from socket import *
from time import ctime
HOST = '' # 此处变量为空白的,这是对bind()方法的标识
PORT = 21567 # 随机选择的且被系统保留的端口号
BUFSIZ = 1024 # 缓冲区大小设置为1KB
ADDR = (HOST, PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM) # 分配了TCP服务器套接字,第一个参数为Python支持的套接字地址家族,第二个参数为套接字类型。
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()
if not data:
break
tcpCliSock.send(('[%s] %s' % (bytes(ctime(), 'utf-8'), data)).encode())
tcpCliSock.close()
tcpSerSock.close()
客户端:
'''
本脚本创建一个TCP客户端,它提示用户输入发送到服务器端的消息,并接收从服务器端返回的添加了时间戳前缀的相同消息,然后将结果展示给用户
'''
from socket import *
HOST = 'localhost' # 因为再本机运行所以设置为localhost(127.0.0.1), 如果在另一台主机运行,那么需要做相应修改。
PORT = 21567 # 端口应与服务器端设置的相同否则无法进行通信
BUFSIZ = 1024
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
while True:
data = input('> ')
if not data:
break
tcpCliSock.send(data.encode())
data = tcpCliSock.recv(BUFSIZ).decode()
if not data:
break
print(data)
tcpCliSock.close()
2.UDP(用户数据报协议):
服务器端:
'''
本脚本创建一个TCP服务器,它接受来自客户端的消息,然后将消息加上时间戳前缀并发送回客户端。
'''
from socket import *
from time import ctime
HOST = ''
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
udpSerSock = socket(AF_INET, SOCK_DGRAM)
udpSerSock.bind(ADDR)
# 因为UDP是无连接的,所以无需调入"监听传入的连接"
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()
客户端:
from socket import *
HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
udpCliSock = socket(AF_INET, SOCK_DGRAM)
while True:
data = input('> ')
if not data:
break
udpCliSock.sendto(data.encode(), ADDR)
data, ADDR = udpCliSock.recvfrom(BUFSIZ)
if not data:
break
print(data)
udpCliSock.close()
之后分别运行服务器端、客户端代码即可进行通信。
3.Twicted Reactor
Twisted 是一个完整的事件驱动的网络架构,利用它既能使用也能开发完整的异步网络应用程序和协议。以下的例子基于Twisted因特网组件中的reactor和protocol子包中的类。
Twicted Reactor TCP 服务器:
from twisted.internet import protocol, reactor
from time import ctime
PORT = 21567
class TSServProtocol(protocol.Protocol):
def connectionMade(self):
clnt = self.clnt = self.transport.getPeer().host
print('··· connected from: ', clnt)
def dataReceived(self, data):
self.transport.write(('[%s] %s' % (ctime(), data)).encode())
factory = protocol.Factory()
factory.protocol = TSServProtocol
print('waiting fot connection··· ')
reactor.listenTCP(PORT, factory)
reactor.run()
Twicted Reactor TCP 客户端:
from twisted.internet import protocol, reactor
HOST = 'localhost'
PORT = 21567
class TSClntProtocol(protocol.Protocol):
def sendData(self):
data = input('> ')
if data:
print('···sending %s ···' % data)
self.transport.write(data.encode())
else:
self.transport.loseConnection()
def connectionMade(self):
self.sendData()
def dataReceived(self, data):
print(data)
self.sendData()
class TSClntFactory(protocol.ClientFactory):
protocol = TSClntProtocol
clientConnectionLost = clientConnectionFailde = lambda self, connector, reason: reactor.stop()
reactor.connectTCP(HOST, PORT, TSClntFactory())
reactor.run()