文章

Python网络编程

Python网络编程

requests 库

requests 是一个基于 HTTP 协议来使用网络的第三库,其 官方网站 有这样的一句介绍它的话:”Requests 是唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。” 简单的说,使用 requests 库可以非常方便的使用 HTTP,避免安全缺陷、冗余代码以及 “ 重复发明轮子 “(行业黑话,通常用在软件工程领域表示重新创造一个已有的或是早已被优化過的基本方法)。

下面我们还是通过 requests 来实现一个访问网络数据接口并从中获取美女图片下载链接然后下载美女图片到本地的例子程序,程序中使用了 天行数据 提供的网络 API。

安装 requests:

1
pip install requests

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from time import time
from threading import Thread

import requests

# 继承Thread类创建自定义的线程类
class DownloadHanlder(Thread):

    def __init__(self, url):
        super().__init__()
        self.url = url

    def run(self):
        filename = self.url[self.url.rfind('/') + 1:]
        resp = requests.get(self.url)
        with open('/Users/Hao/' + filename, 'wb') as f:
            f.write(resp.content)


def main():
    # 通过requests模块的get函数获取网络资源
    # 下面的代码中使用了天行数据接口提供的网络API
    # 要使用该数据接口需要在天行数据的网站上注册
    # 然后用自己的Key替换掉下面代码的中APIKey即可
    resp = requests.get(
        'http://api.tianapi.com/meinv/?key=APIKey&num=10')
    # 将服务器返回的JSON格式的数据解析为字典
    data_model = resp.json()
    for mm_dict in data_model['newslist']:
        url = mm_dict['picUrl']
        # 通过多线程的方式实现图片下载
        DownloadHanlder(url).start()


if __name__ == '__main__':
    main()

基于传输层协议的套接字编程

TCP 套接字

所谓 TCP 套接字就是使用 TCP 协议提供的传输服务来实现网络通信的编程接口。在 Python 中可以通过创建 socket 对象并指定 type 属性为 SOCK_STREAM 来使用 TCP 套接字。由于一台主机可能拥有多个 IP 地址,而且很有可能会配置多个不同的服务,所以作为服务器端的程序,需要在创建套接字对象后将其绑定到指定的 IP 地址和端口上。这里的端口并不是物理设备而是对 IP 地址的扩展,用于区分不同的服务,例如我们通常将 HTTP 服务跟 80 端口绑定,而 MySQL 数据库服务默认绑定在 3306 端口,这样当服务器收到用户请求时就可以根据端口号来确定到底用户请求的是 HTTP 服务器还是数据库服务器提供的服务。端口的取值范围是 0~65535,而 1024 以下的端口我们通常称之为 “ 著名端口 “(留给像 FTP、HTTP、SMTP 等 “ 著名服务 “ 使用的端口,有的地方也称之为 “ 周知端口 “),自定义的服务通常不使用这些端口,除非自定义的是 HTTP 或 FTP 这样的著名服务。

下面的代码实现了一个提供时间日期的服务器。

  • 服务端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from socket import socket, SOCK_STREAM, AF_INET
from datetime import datetime


def main():
    # 1.创建套接字对象并指定使用哪种传输服务
    # family=AF_INET - IPv4地址
    # family=AF_INET6 - IPv6地址
    # type=SOCK_STREAM - TCP套接字
    # type=SOCK_DGRAM - UDP套接字
    # type=SOCK_RAW - 原始套接字
    server = socket(family=AF_INET, type=SOCK_STREAM)
    # 2.绑定IP地址和端口(端口用于区分不同的服务)
    # 同一时间在同一个端口上只能绑定一个服务否则报错
    server.bind(('192.168.1.2', 6789))
    # 3.开启监听 - 监听客户端连接到服务器
    # 参数512可以理解为连接队列的大小
    server.listen(512)
    print('服务器启动开始监听...')
    while True:
        # 4.通过循环接收客户端的连接并作出相应的处理(提供服务)
        # accept方法是一个阻塞方法如果没有客户端连接到服务器代码不会向下执行
        # accept方法返回一个元组其中的第一个元素是客户端对象
        # 第二个元素是连接到服务器的客户端的地址(由IP和端口两部分构成)
        client, addr = server.accept()
        print(str(addr) + '连接到了服务器.')
        # 5.发送数据
        client.send(str(datetime.now()).encode('utf-8'))
        # 6.断开连接
        client.close()


if __name__ == '__main__':
    main()
  • 客户端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from socket import socket


def main():
    # 1.创建套接字对象默认使用IPv4和TCP协议
    client = socket()
    # 2.连接到服务器(需要指定IP地址和端口)
    client.connect(('192.168.1.2', 6789))
    # 3.从服务器接收数据
    print(client.recv(1024).decode('utf-8'))
    client.close()


if __name__ == '__main__':
    main()

UDP 套接字

传输层除了有可靠的传输协议 TCP 之外,还有一种非常轻便的传输协议叫做用户数据报协议,简称 UDP。TCP 和 UDP 都是提供端到端传输服务的协议,二者的差别就如同打电话和发短信的区别,后者不对传输的可靠性和可达性做出任何承诺从而避免了 TCP 中握手和重传的开销,所以在强调性能和而不是数据完整性的场景中(例如传输网络音视频数据),UDP 可能是更好的选择。可能大家会注意到一个现象,就是在观看网络视频时,有时会出现卡顿,有时会出现花屏,这无非就是部分数据传丢或传错造成的。在 Python 中也可以使用 UDP 套接字来创建网络应用。

本文由作者按照 CC BY 4.0 进行授权