python----网络编程(TCP通讯)

python----网络编程(TCP通讯)

笔者在学习Python核心编程(第三版)这本书籍的时候

在章节网络编程 2.4.1----TCP服务端和客户端里面

尝试按照书籍编写TCP服务端和客户端的程序

书籍例子如下

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’ 

笔者纠结了很久,在百度上搜索了相关的文章,看到了作者“MrYx”的一篇文章

https://blog.csdn.net/yexiaohhjk/article/details/68066843

里面有说道

In python 3, bytes strings and unicode strings are now two different types. Since sockets are not aware of string encodings, they are using raw bytes strings, that have a slightly different interface from unicode strings.

So, now, whenever you have a unicode string that you need to use as a byte string, you need to encode() 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 enclosed strings. 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()


这里大致的意思就是,Pyhon3之后,bytes strings 和 unicode strings 是两种不同的字符类型。如果想要将unicode strings变成bytes strings,我们需要用encode()这种方式去对其进行转码。反之,我们则需要用到decode()。而在书籍的例子里面,在关于变量data,并没有考虑到这点。我们从socket里面接受或者发送的数据,应该是bytes类型的,但是我们在程序里面编辑的时候,需要的字符类型是unicode的,因此,我们需要对书籍的例子作出修改。

修改如下

TCP服务端

#!/usr/bin/python3
#-*- coding -*-

from socket import *
from time import ctime

HOST = ''
PORT = 21571
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()
        if not data:
            break
        tcpCliSock.send(('[%s] %s' %(ctime(),data)).encode())

    tcpCliSock.close()
tcpCliSock.close()

TCP客户端

#!/usr/bin/python3
#-*- coding -*-

from  socket import *

HOST = '127.0.0.1'
PORT = 21571
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()

twisted:

服务端

#!/usr/bin/python3
#-*- coding -*-

from twisted.internet import protocol,reactor
from time import ctime

PORT = 21500

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 for connection...')
reactor.listenTCP(PORT,factory)
reactor.run()

客户端

#!/usr/bin/python3
#-*- coding -*-

from twisted.internet import protocol,reactor

HOST = 'localhost'
PORT = 21500

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):
        self.sendData()

class TSClntFactory(protocol.ClientFactory):
    protocol = TSClntProtocol
    clientConnectionLost = clientConnentionFailed = 
        lambda self,connector,reason:reactor.stop()

reactor.connectTCP(HOST,PORT,TSClntFactory())
reactor.run()

本文参考

https://blog.csdn.net/yexiaohhjk/article/details/68066843

原文地址:https://www.cnblogs.com/QicongLiang/p/10096969.html