Python 核心编程 2 -- 网络编程

版权声明:转载请注明出处 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()

感谢作者MrYx对该章节中报错贡献的解决方案

猜你喜欢

转载自blog.csdn.net/weixin_39653948/article/details/82986258