第十四章 网络编程
鉴于Python提供的网络工具众多,这里只能简要地介绍它的网络功能。 本章首先概述Python标准库中的一些网络模块。然后讨论SocketServer和相关的类,并介绍 地介绍同时处理多个连接的各种方法。最后,简单地说一说Twisted,这是一个使用Python编写网 络程序的框架,功能丰富而成熟。
14.1 几个网络模块
14.1.1 模块 socket
网络编程中的一个基本组件是套接字(socket)。套接字基本上是一个信息通道,两端各有一 个程序。在Python中,大多数网络编程都隐藏了模块socket的基本工作原理,不与套接字直接交互。
套接字分为两类:服务器套接字和客户端套接字。创建服务器套接字后,让它等待连接请求 的到来。这样,它将在某个网络地址(由IP地址和端口号组成)处监听,直到客户端套接字建立 连接。随后,客户端和服务器就能通信了。
客户端套接字处理起来通常比服务器端套接字容易些,因为服务器必须准备随时处理客户端 连接,还必须处理多个连接;而客户端只需连接,完成任务后再断开连接即可。
本章后面将介绍 如何使用SocketServer等类和Twisted框架进行服务器端编程。
套接字是模块socket中socket类的实例。函数格式为:
socket(family,type[,protocol])
实例化套接字时最多可指定三个参数:一个地址族 (family,默认为socket.AF_INET);一个是socket类型是流套接字(typ,默认设置socket.SOCK_STREAM,)还是数据报套接字 (socket.SOCK_DGRAM);一个是协议类型(protocol,使用默认值0就好)。创建普通套接字时,不用提供任何参数。
地址族(又称协议族):
| Family参数 | 描述 |
| --------------- | ---------------------------------- |
| socket.AF_UNIX | 只能够用于单一的Unix系统进程间通信 |
| socket.AF_INET | 服务器之间网络通信 ipv4 |
| socket.AF_INET6 | IPv6 |
socket类型:
| Type参数 | 描述 |
| ------------------ | ------------------------------------------------------------ |
| socket.SOCK_STREAM | 流式socket , 当使用TCP时选择此参数 |
| socket.SOCK_DGRAM | 数据报式socket ,当使用UDP时选择此参数 |
| socket.SOCK_RAW | 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头Type参数 |
协议类型 :
| protocol参数 | 描述 |
| ------------------ | ------------------------------------------------------------ |
| socket.IPPROTO_RAW | 相当于protocol=255,此时socket只能用来发送IP包,而不能接收任何的数据。发送的数据需要自己填充IP包头,并且自己计算校验和 |
| socket.IPPROTO_IP | 相当于protocol=0,此时用于接收任何的IP数据包。其中的校验和和协议分析由程序自己完成 |
服务器套接字先调用方法bind,再调用方法listen来监听特定的地址。然后,客户端套接字 就可连接到服务器了,办法是调用方法connect并提供调用方法bind时指定的地址(在服务器端, 可使用函数socket.gethostname获取当前机器的主机名)。这里的地址是一个格式为(host, port) 的元组,其中host是主机名(如www.example.com),而port是端口号(一个整数)。方法listen接 受一个参数——待办任务清单的长度(即最多可有多少个连接在队列中等待接纳,到达这个数量 后将开始拒绝连接)。
服务器套接字开始监听后,就可接受客户端连接了,这是使用方法accept来完成的。这个方 法将阻断(等待)到客户端连接到来为止,然后返回一个格式为(client, address)的元组,其中 client是一个客户端套接字,而address是前面解释过的地址。服务器能以其认为合适的方式处 理客户端连接,然后再次调用accept以接着等待新连接到来。这通常是在一个无限循环中完成的。
为传输数据,套接字提供了两个方法:send和recv(表示receive)。要发送数据,可调用方 法send并提供一个字符串;要接收数据,可调用recv并指定最多接收多少个字节的数据。如果不 确定该指定什么数字,1024是个不错的选择。
以下是两个最简单的客户端程序和服务器程序。
```python
#serve.py
import socket
s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host, port))
s.listen(5)
c, addr = s.accept()
print('Got connection from', addr)
while True:
c.send(b'Thank you for connecting')
c.close()
```
```python
#client.py
import socket
s = socket.socket()
host = socket.gethostname()
port = 1234
s.connect((host, port))
print(s.recv(1024))
```
结果:
```
C:\Users\xx\AppData\Local\Programs\Python\Python37\python.exe E:/pythonProjects/gui
b'Thank you for connecting'
Process finished with exit code 0
```
14.1.2 模块 urllib 和 urllib2
1、打开远程文件
几乎可以像打开本地文件一样打开远程文件,差别是只能使用读取模式,以及使用模块 urllib.request中的函数urlopen,而不是open(或file)。
```python
from urllib.request import urlopen
webpage = urlopen('http://www.python.org')
w=webpage.read(200)
print(w)
```
结果:
```
C:\Users\xx\AppData\Local\Programs\Python\Python37\python.exe E:/pythonProjects/print.py
b'\n\n\n\n\n