Python网络编程

 

 

1  套接字(socker):通信端点

服务器创建一个通信端点使服务器监听请求,客户端创建一个通信端点建立一个到服务器的连接

1.1  套接字

有两种类型的套接字:基于文件的和基于网络的

1.1.1   基于文件的套接字

基于文件的套接字:两个进程运行在同一台计算机上

AF_UNIX(又名AF_LOCAL):代表地址家族(address family):UNIX

其他比较旧的系统可能会将地址家族表示成域(domain)或协议家族(protocol family),缩写PF

1.1.2   基于网络的套接字

1)  AF_INET:地址家族:因特网(最广泛)

AF_INET6:第6版因特网协议(IPV6)寻址

1.1.3   Python中引入对特殊类型的Linux套接字

1)  AF_NETLINK:无连接,允许使用标准的BSD(加利福尼亚大学的伯克利版本)套接字接口进行用户级别和内核级别代码之间的IPC(通信进程:Inter Process Communication)

2)  AF_TIPC:支持透明的进程间通信协议,允许计算机集群之中的机器互相通信,而无需使用基于IP的寻址方式

1.2  套接字地址:主机-端口对

一个网络地址由主机名和端口号对组成,有效的端口号范围为0~65535(小于1024的端口号预留给了系统)

1.3  面向连接的套接字与无连接的套接字

不管采用的是哪种地址家族,都有两种不同风格的套接字连接(面向连接的套接字和无连接的套接字)

1.3.1   面向连接的套接字

在进行通信之前必须先建立一个连接,实现这种连接类型的主要协议是传输控制协议(TCP),每条消息可以拆分成多个片段,并且每一条消息片段都确保能够到达目的地。

创建TCP 套接字,必须使用SOCK_STREAM 作为套接字类型(AF_INET套接字与TCP)

1.3.2   无连接的套接字

在通信开始之前并不需要建立连接,实现这种连接类型的主要协议是用户数据报协议(UDP),消息是以整体发送的。

创建UDP 套接字,必须使用SOCK_DGRAM 作为套接字类型(AF_INET套接字与UDP)

2  Python中的网络编程socket模块

主要模块是socket 模块,在这个模块中可以找到socket()函数,该函数用于创建套接字对象

2.1  socket()模块函数

创建套接字,必须使用socket.socket()函数,它一般的语法如下:

socket(socket_family, socket_type, protocol=0)

其中,socket_family是AF_UNIX或AF_INET,socket_type是SOCK_STREAM或SOCK_DGRAM。protocol通常省略,默认为0。

例:

tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

使用from socket import *,则:

tcpSock = socket(AF_INET, SOCK_STREAM)

2.2  套接字对象(内置)方法

名称

描述

服务器套接字方法

s.bind()

将地址(主机名、端口号对)绑定到套接字上

s.listen()

设置并启动TCP 监听器

s.accept()

被动接受TCP 客户端连接,一直等待直到连接到达(阻塞)

客户端套接字方法

s.connect()

主动发起TCP 服务器连接

s.connect_ex()

connect()的扩展版本,此时会以错误码的形式返回问题,而不是抛出一个异常

普通的套接字方法

s.recv()

接收TCP 消息

s.recv_into()

接收TCP 消息到指定的缓冲区

s.send()

发送TCP 消息

s.sendall()

完整地发送TCP 消息

s.recvfrom()

接收UDP 消息

s.recvfrom_into()

接收UDP 消息到指定的缓冲区

s.sendto()

发送UDP 消息

s.getpeername()

连接到套接字(TCP)的远程地址

s.getsockname()

当前套接字的地址

s.getsockopt()

返回给定套接字选项的值

s.setsockopt()

设置给定套接字选项的值

s.shutdown()

关闭连接

s.close()

关闭套接字

s.detach()

在未关闭文件描述符的情况下关闭套接字,返回文件描述符

s.ioctl()

控制套接字的模式(仅支持Windows)

面向阻塞的套接字方法

s.setblocking()

设置套接字的阻塞或非阻塞模式

s.settimeout()

设置阻塞套接字操作的超时时间

s.gettimeout()

获取阻塞套接字操作的超时时间

面向文件的套接字方法

s.fileno()

套接字的文件描述符

s.makefile()

创建与套接字关联的文件对象

数据属性

s.family

套接字家族

s.type

套接字类型

s.proto

套接字协议

2.3  创建TCP服务器

1)  通用TCP服务器的一般伪代码

ss = socket() # 创建服务器套接字
s.bind() # 套接字与地址绑定
ss.listen() # 监听连接
inf_loop: # 服务器无限循环
  cs = ss.accept() # 接受客户端连接
  comm_loop: # 通信循环
    cs.recv()/cs.send() # 对话(接收/发送)
  cs.close() # 关闭客户端套接字
ss .close() # 关闭服务器套接字#(可选)

ss.bind()服务器需要绑定到一个本地地址和占用一个端口。ss.listen()监听(传入)的连接。

ss.accept()开启一个简单的(单线程)服务器等待客户端的连接,是阻塞的,意味着执行将被暂停,直到一个连接到达,一旦服务器接收了一个连接,就会返回(利用accept())一个独立的客户端套接字,用来与即将到来的消息进行交换(当一个传入的请求到达时,服务器会创建一个新的通信端口来直接与客户端进行通信,再次空出主要的端口,以使其能够接受新的客户端连接);

2)  创建TCP服务器代码

 1 '''
 2 创建TCP服务器
 3 '''
 4 
 5 from socket import *
 6 from time import ctime
 7 
 8 HOST = ''            #空白表示可以使用任何可用的地址,是对bind()方法的标识
 9 PORT = 21567         #端口
10 BUFSIZ = 1024        #缓冲区大小设置为1KB,可根据网络性能和程序需要改变这个容量
11 ADDR = (HOST,PORT)   
12 
13 tcpSerSock = socket(AF_INET,SOCK_STREAM)   #创建套接字
14 tcpSerSock.bind(ADDR)                      #将套接字绑定到服务器地址和端口
15 tcpSerSock.listen(1)                       #开启TCP监听,参数是传入连接在排队的请求的最大数,设置为0和1相同
16 
17 while True:
18     print('waiting for connection...')
19     tcpCliSock,addr = tcpSerSock.accept()  #生成一个包含socket对象(tcpClisock)和连接的IP地址、端口(addr)的元组
20     print('...connected from:',addr)
21 
22     while True:
23         data = (tcpCliSock.recv(BUFSIZ)).decode('utf-8')  #接收客户端发来的TCP消息
24         if not data:
25             break
26 
27         #发送给客户端的TCP消息,使用utf-8编码转成二进制数据发送,只能转成二进制数据才能发送
28         tcpCliSock.send(bytes(('[%s] %s' % (ctime(),data)),'utf-8'))   
29 
30     tcpCliSock.close()   #关闭当前客户端连接,然后等待另一个客户端连接
31 tcpSerSock.close()       #这一行在这个程序里永远不会执行,只是提醒可以使用这个来考虑一个更优雅的退出方式

3)创建TCP客户端伪代码

cs = socket() # 创建客户端套接字
cs.connect() # 尝试连接服务器
comm_loop: # 通信循环
    cs.send()/cs.recv() # 对话(发送/接收)
cs .close() # 关闭客户端套接字

4)  创建TCP客户端代码

 1 '''
 2 创建TCP客户端
 3 '''
 4 
 5 from socket import *
 6 
 7 HOST = 'localhost'
 8 PORT = 21567          #端口号应与服务器设置的完成相同
 9 BUFSIZ = 1024
10 ADDR = (HOST,PORT)
11 
12 tcpCliSOCK = socket(AF_INET,SOCK_STREAM)
13 tcpCliSOCK.connect(ADDR)   #主动调用并连接服务器
14 
15 while True:
16     data = input('>')
17     if not data:
18         break
19 
20     #发送给服务器的TCP消息,使用utf-8编码转成二进制数据发送,只能转成二进制数据才能发送
21     tcpCliSOCK.send(bytes(data,'utf-8'))   
22     data = tcpCliSOCK.recv(BUFSIZ)    #接收服务器发来的TCP消息
23     if not data:
24         break
25     print(data.decode('utf-8'))
26 tcpCliSOCK.close()

5)  执行TCP服务器和客户端

执行TCP服务器

执行TCP客户端

2.4  创建UDP服务器

UDP因为数据报套接字是无连接的,所以就没有为了成功通信而使一个客户端连接到一个独立的套接字“转换”的操作。这些服务器仅仅接受消息并有可能回复数据。

1)  创建UDP服务器的伪代码

ss = socket() # 创建服务器套接字
ss.bind() # 绑定服务器套接字
inf_loop: # 服务器无限循环
    cs = ss.recvfrom()/ss.sendto() # 关闭(接收/发送)
ss .close() # 关闭服务器套接字

2)  创建UDP服务器代码

 1 '''
 2 创建UDP服务器
 3 '''
 4 
 5 from socket import *
 6 from time import ctime
 7 
 8 HOST = ''            #空白表示可以使用任何可用的地址,是对bind()方法的标识
 9 PORT = 21567         #端口
10 BUFSIZ = 1024        #缓冲区大小设置为1KB,可根据网络性能和程序需要改变这个容量
11 ADDR = (HOST,PORT)   
12 
13 udpSerSock = socket(AF_INET,SOCK_DGRAM)   #创建套接字
14 udpSerSock.bind(ADDR)                      #将套接字绑定到服务器地址和端口
15 
16 while True:
17     print('waiting for message...')
18     data,addr = udpSerSock.recvfrom(BUFSIZ)  #接收客户端发来的UDP消息,此消息包含客户端发来数据和客户端地址、端口号的元组
19 
20     #发送给客户端的UDP消息,使用utf-8编码转成二进制数据发送,只能转成二进制数据才能发送
21     udpSerSock.sendto(('[%s] %s' % (ctime(),data.decode('utf-8'))).encode('utf-8'),addr)   
22     print('...received from and returned to:',addr)
23 udpSerSock.close()       #这一行在这个程序里永远不会执行,只是提醒可以使用这个来考虑一个更优雅的退出方式

3)  创建UDP客户端伪代码

cs = socket() # 创建客户端套接字
comm_loop: # 通信循环
    cs.sendto()/cs.recvfrom() # 对话(发送/接收)
cs .close() # 关闭客户端套接字

4)  创建UDP客户端代码

 1 '''
 2 创建UDP客户端
 3 '''
 4 
 5 from socket import *
 6 
 7 HOST = b'localhost'
 8 PORT = 21567          #端口号应与服务器设置的完成相同
 9 BUFSIZ = 1024
10 ADDR = (HOST,PORT)
11 
12 udpCliSOCK = socket(AF_INET,SOCK_DGRAM)
13 
14 while True:
15     data = input('>')
16     if not data:
17         break
18 
19     #发送给服务器的UDP消息,使用utf-8编码转成二进制数据发送,只能转成二进制数据才能发送
20     udpCliSOCK.sendto(data.encode('utf-8'),ADDR) 
21     data,ADDR = udpCliSOCK.recvfrom(BUFSIZ)    #接收服务器发来的UDP消息
22     if not data:
23         break
24     print(data.decode('utf-8'))
25 udpCliSOCK.close()

5)  执行TCP服务器和客户端

执行UDP服务器

执行UDP客户端

3  Python中的网络编程socketserver模块

socketserver是标准库中的一个高级模块,目标是简化很多样板代码

3.1  socketserver模块类

描述

TCPServer/UDPServer

基础的网络同步TCP/UDP 服务器

UnixStreamServer/UnixDatagramServer

基于文件的基础同步TCP/UDP 服务器

ForkingTCPServer/ForkingUDPServer

ForkingMixIn 和TCPServer/UDPServer 的组合

ThreadingTCPServer/ThreadingUDPServer

ThreadingMixIn 和TCPServer/UDPServer 的组合

BaseRequestHandler

包含处理服务请求的核心功能;仅仅用于推导,这样无法创建这个类的实例;

可以使用StreamRequestHandler 或DatagramRequestHandler 创建类的实例

3.2  创建socketserver TCP服务器

 1 '''
 2 创建TCP服务器
 3 '''
 4 
 5 from socketserver import (TCPServer as TCP,StreamRequestHandler as SRH)
 6 from time import ctime
 7 
 8 HOST = ''            #空白表示可以使用任何可用的地址
 9 PORT = 21567         #端口
10 ADDR = (HOST,PORT)   
11 
12 class MyRequestHandler(SRH):    #MyRequestHandler作为StreamRequestHandler的一个子类
13     #当接收到一个来自客户端的消息时,它就会调用handle()方法
14     def handle(self):
15         print('...connected from:',self.client_address)
16         #StreamRequestHandler类将输入和输出套接字看作类似文件的对象,
17         #将使用readline()来获取客户端消息,并利用write()将字符串发送回客户端
18         #因此,在客户端和服务器代码中,需要额外的回车和换行符
19         self.wfile.write(('[%s] %s' % (ctime(),self.rfile.readline().decode('utf-8'))).encode('utf-8'))
20 
21 tcpServ = TCP(ADDR,MyRequestHandler)   #创建TCP 服务器
22 print('waiting for connection...')
23 tcpServ.serve_forever()           #无限循环地等待并服务于客户端请求

3.3  创建socketserver TCP客户端

 1 '''
 2 创建TCP客户端
 3 '''
 4 
 5 from socket import *
 6 
 7 HOST = 'localhost'
 8 PORT = 21567          #端口号应与服务器设置的完成相同
 9 BUFSIZ = 1024
10 ADDR = (HOST,PORT)
11 
12 while True:
13     tcpCliSOCK = socket(AF_INET,SOCK_STREAM)
14     tcpCliSOCK.connect(ADDR)
15     data = input('>')
16     if not data:
17         break
18 
19     #发送给服务器的TCP消息,使用utf-8编码转成二进制数据发送,只能转成二进制数据才能发送
20     #服务端将输入和输出套接字看作类似文件的对象,需要额外的回车和换行符
21     tcpCliSOCK.send(('%s\r\n' % data).encode('utf-8')) 
22     data = tcpCliSOCK.recv(BUFSIZ)    #接收服务器发来的TCP消息
23     if not data:
24         break
25     print(data.decode('utf-8').strip())
26     tcpCliSOCK.close()

3.4  执行TCP服务器和客户端

TCP服务器输出

TCP客户端输出

4  Python中的网络编程twisted框架

Twisted 是一个完整的事件驱动的网络框架,利用它既能使用也能开发完整的异步网络应用程序和协议,不是Python 标准库的一部分

4.1  下载与安装twisted

python3.6版本pip install twisted会报错,在Python扩展包的非官方Windows二进制文件里https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下载Twisted-18.7.0-cp36-cp36m-win_amd64.whl,

pip install Twisted-18.7.0-cp36-cp36m-win_amd64.whl进行安装

4.2  创建Twisted Reactor TCP服务器代码

 1 '''
 2 创建TCP服务器
 3 '''
 4 
 5 from twisted.internet import protocol,reactor
 6 import re
 7 from time import ctime
 8 
 9 PORT = 21567         #端口
10  
11 class TSServProtocol(protocol.Protocol):   
12     #重写connectionMade()方法,当一个客户端连接到服务器时就会执行connectionMade()方法
13     def connectionMade(self):    
14         clnt = self.clnt = self.transport.getPeer().host  #获取主机信息
15         print('...connected from:',clnt)
16     #重写dataReceived()方法,当服务器接收到客户端通过网络发送的一些数据时就会调用dataReceived()方法
17     def dataReceived(self,data):
18         self.transport.write(('[%s] %s' % (ctime(),data.decode('utf-8'))).encode('utf-8')) #将数据返回给客户
19 
20 factory = protocol.Factory()   #创建了一个协议工厂
21 factory.protocol = TSServProtocol  #每次得到一个接入连接时,都能“制造”协议的一个实例
22 print('waiting for connection...')
23 #TCP监听器,当接收到一个请求时,就会创建一个TSServProtocol实例来处理那个客户端的事务。
24 reactor.listenTCP(PORT,factory)   
25 reactor.run()

4.3  创建Twisted Reactor TCP客户端代码

'''
创建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('utf-8'))  ##将数据发送给服务器
        else:
             self.transport.loseConnection() #不输入任何内容来关闭连接

     #重写connectionMade()方法,当一个客户端连接到服务器时就会执行connectionMade()方法
    def connectionMade(self):  
         self.sendData()

     #重写dataReceived()方法,当客户端接收到服务器通过网络发送的一些数据时就会调用dataReceived()方法
    def dataReceived(self,data): 
         print(data.decode('utf-8'))
         self.sendData()

class TSClntFactory(protocol.ClientFactory):
    protocol = TSClntProtocol
    #某些其他的原因而导致系统调用了clientConnectionFailed(),那么也会停止reactor
    clientConnectionLost = clientConnectionLostFailed = lambda self,connector,reason:reactor.stop()

#创建了一个客户端工厂,一个到服务器的连接并运行reactor
#实例化了客户端工厂TSClntFactory(),因为是一个客户端,所以创建单个连接到服务器的协议对象
reactor.connectTCP(HOST,PORT,TSClntFactory())  
reactor.run()

4.4  执行TCP服务器和客户端

执行TCP服务器

执行TCP客户端

5  Python中的网络编程相关模块

5.1  网络/套接字编程相关模块

模块

描述

socket

是低级网络编程接口

asyncore/asynchat

提供创建网络应用程序的基础设施,并异步地处理客户端

select

在一个单线程的网络服务器应用中管理多个套接字连接

SocketServer

高级模块,提供网络应用程序的服务器类,包括forking 或threading 簇

1)  select模块和socket 模块

当开发低级套接字程序时,经常配合使用select 模块和socket 模块。select 模块提供了select()函数,该函数管理套接字对象集合。它所做的最有用的一个事情就是接收一套套接字,并监听它们活动的连接。select()函数将会阻塞。

2)  async*和SocketServer 模块

async*和SocketServer 模块都提供更高级的功能。它们以socket 和/或select 模块为基础编写,能够使客户端/服务器系统开发更加迅速,因为它们已经自动处理了所有的底层代码。你需要做的所有工作就是以自己的方式创建或继承适当的基类。

3)  Concurrence现代化的网络框架

Concurrence 是一个搭配了libevent 的高性能I/O 系统,libevent 是一个低级事件回调调度系统。Concurrence 是一个异步模型,它使用轻量级线程(执行回调)以事件驱动的方式进行线程间通信和消息传递工作。

现代网络框架遵循众多异步模型(greenlet、generator 等)之一来提供高性能异步服务器

转载于:https://www.cnblogs.com/longBlogs/p/9761836.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值