Skip to content

Latest commit

 

History

History
293 lines (187 loc) · 19.5 KB

File metadata and controls

293 lines (187 loc) · 19.5 KB

十、基本网络——套接字编程

在本章中,您将学习套接字和三种 internet 协议:http、ftplib和urllib。您还将了解 Python 中用于联网的socket模块。http是用于使用超文本传输协议(HTTP的包。ftplib模块用于执行自动 FTP 相关工作。urllib是一个处理 URL 相关工作的包。

在本章中,您将了解以下内容:

  • 插座
  • http包
  • ftplib模块
  • urllib包

插座

在本节中,我们将学习套接字。我们将使用 Python 的套接字模块。套接字是机器之间通信的端点,无论是本地通信还是通过 internet 通信。socket 模块有一个 socket 类,用于处理数据通道。它还具有网络相关任务的功能。要使用 socket 模块的功能,我们首先需要导入 socket 模块。

让我们看看如何创建套接字。socket 类有一个 socket 函数,有两个参数:address_family和socket type。

以下是语法:

 import socket            s = socket.socket(address_family, socket type)

address_family控制 OSI 网络层协议。

**socket type**控制传输层协议。

Python 支持三个地址族:AF_INET、AF_INET6和AF_UNIX。最常用的是AF_INET,用于互联网寻址。AF_INET6用于 IPv6 互联网寻址。AF_UNIX用于Unix 域套接字(UDS),是进程间通信协议。

有两种插座类型:SOCK_DGRAM和SOCK_STREAM。SOCK_DGRAM套接字类型用于面向消息的数据报传输;这些都与 UDP 相关联。数据报套接字传递单独的消息。SOCK_STREAM用于流式运输;这些与 TCP 相关。流套接字在客户端和服务器之间提供字节流。

套接字可以配置为服务器和客户端套接字。当两个 TCP/IP 套接字都连接时,通信将是双向的。现在我们将探索一个客户机-服务器通信的示例。我们将创建两个脚本:server.py和client.py。

server.py脚本如下:

import socket host_name = socket.gethostname() port = 5000 s_socket = socket.socket() s_socket.bind((host_name, port)) s_socket.listen(2) conn, address = s_socket.accept() print("Connection from: " + str(address)) while True:
 recv_data = conn.recv(1024).decode() if not recv_data: break print("from connected user: " + str(recv_data)) recv_data = input(' -> ') conn.send(recv_data.encode()) conn.close()

现在我们将为客户端编写一个脚本。

client.py脚本如下:

import socket host_name = socket.gethostname() port = 5000 c_socket = socket.socket() c_socket.connect((host_name, port)) msg = input(" -> ")  while msg.lower().strip() != 'bye': c_socket.send(msg.encode()) recv_data = c_socket.recv(1024).decode() print('Received from server: ' + recv_data) msg = input(" -> ") c_socket.close()

现在我们将在两个不同的终端上运行这两个程序。在第一个终端运行server.py,在第二个终端运行client.py。

输出结果如下:

| 端子 1:python3 server.py | 终端 2:python3 client.py | | student@ubuntu:~/work$ python3 server.py``Connection from: ('127.0.0.1', 35120)``from connected user: Hello from client`` -> Hello from server ! | student@ubuntu:~/work$ python3 client.py``-> Hello from client``Received from server: Hello from server !`` -> |

http 包

在本节中,我们将了解http包。http包有四个模块:

  • http.client:这是一个底层 HTTP 协议客户端
  • http.server:包含基本的 HTTP 服务器类
  • http.cookies:用于对 cookie 进行状态管理
  • http.cookiejar:此模块提供 cookie 持久性

在本节中,我们将学习http.client和http.server模块。

http.client 模块

我们将看到两个http请求:GET和POST。我们还将建立一个http连接。

首先,我们将探索一个建立http连接的示例。为此,创建一个make_connection.py脚本,并在其中写入以下内容:

import http.client con_obj = http.client.HTTPConnection('Enter_URL_name', 80, timeout=20) print(con_obj)

运行脚本,您将获得如下输出:

student@ubuntu:~/work$ python3 make_connection.py <http.client.HTTPConnection object at 0x7f2c365dd898>

在前面的示例中,我们与端口 80 上提到的 URL 建立了一个特定超时的连接。

现在我们将看到http``GET请求方法;使用这个GET请求方法,我们将看到一个示例,其中我们得到一个响应代码以及一个标题列表。创建一个get_example.py脚本,并在其中写入以下内容:

import http.client con_obj = http.client.HTTPSConnection("www.imdb.com") con_obj.request("GET", "/") response = con_obj.getresponse()  print("Status: {}".format(response.status))  headers_list = response.getheaders()
print("Headers: {}".format(headers_list))  con_obj.close()

按如下方式运行脚本:

student@ubuntu:~/work$ python3 get_example.py

输出应如下所示:

Status: 200 Headers: [('Server', 'Server'), ('Date', 'Fri, 23 Nov 2018 09:49:12 GMT'), ('Content-Type', 'text/html;charset=UTF-8'), ('Transfer-Encoding', 'chunked'), ('Connection', 'keep-alive'), ('X-Frame-Options', 'SAMEORIGIN'), ('Content-Security-Policy', "frame-ancestors 'self' imdb.com *.imdb.com *.media-imdb.com withoutabox.com *.withoutabox.com amazon.com *.amazon.com amazon.co.uk *.amazon.co.uk amazon.de *.amazon.de translate.google.com images.google.com www.google.com www.google.co.uk search.aol.com bing.com www.bing.com"), ('Ad-Unit', 'imdb.home.homepage'), ('Entity-Id', ''), ('Section-Id', 'homepage'), ('Page-Id', 'homepage'), ('Content-Language', 'en-US'), ('Set-Cookie', 'uu=BCYsgIz6VTPefAjQB9YlJiZhwogwHmoU3sLx9YK-A61kPgvXEKwHSJKU3XeaxIoL8DBQGhYLuFvR%0D%0AqPV6VVvx70AV6eL_sGzVaRQQAKf-PUz2y0sTx9H4Yvib9iSYRPOzR5qHQkwuoHPKmpu2KsSbPaCb%0D%0AYbc-R6nz9ObkbQf6RAYm5sTAdf5lSqM2ZzCEhfIt_H3tWQqnK5WlihYwfMZS2AJdtGXGRnRvEHlv%0D%0AyA4Dcn9NyeX44-hAnS64zkDfDeGXoCUic_kH6ZnD5vv21HOiVodVKA%0D%0A; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 13:03:18 GMT; Path=/; Secure'), ('Set-Cookie', 'session-id=134-6809939-6044806; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 13:03:18 GMT; Path=/; Secure'), ('Set-Cookie', 'session-id-time=2173686551; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 13:03:18 GMT; Path=/; Secure'), ('Vary', 'Accept-Encoding,X-Amzn-CDN-Cache,User-Agent'), ('x-amz-rid', '7SWEYTYH4TX8YR2CF5JT')]

在前面的示例中,我们使用了HTTPSConnection,因为网站是通过HTTPS协议提供服务的。您可以使用HTTPSConnection或HTTPConnection,具体取决于您使用的网站。我们提供了一个 URL 并检查了连接对象的状态。在那之后,我们得到了一个标题列表。此标题列表包含有关从服务器发回的数据类型的信息。getheaders()方法将获取标题列表。

现在我们将看到一个POST请求的示例。我们可以使用HTTP POST将数据发布到 URL。为此,创建一个post_example.py脚本,并在其中写入以下内容:

import http.client import json con_obj = http.client.HTTPSConnection('www.httpbin.org') headers_list = {'Content-type': 'application/json'} post_text = {'text': 'Hello World !!'} json_data = json.dumps(post_text) con_obj.request('POST', '/post', json_data, headers_list) response = con_obj.getresponse() print(response.read().decode())

按如下方式运行脚本:

student@ubuntu:~/work$ python3 post_example.py

您应该获得以下输出:

{
 "args": {}, "data": "{\"text\": \"Hello World !!\"}", "files": {}, "form": {}, "headers": { "Accept-Encoding": "identity", "Connection": "close", "Content-Length": "26", "Content-Type": "application/json", "Host": "www.httpbin.org" }, "json": { "text": "Hello World !!" }, "origin": "1.186.106.115", "url": "https://www.httpbin.org/post" }

在前面的示例中,我们首先创建了一个HTTPSConnection对象。接下来,我们创建了一个post_text对象,它发布Hello World。之后,我们写了一个POST请求,并收到了回复。

http.server 模块

在本节中,我们将学习来自http包的模块http.server模块。此模块定义用于实现HTTP服务器的类。有两种方式:GET和HEAD。通过使用此模块,我们可以通过网络共享文件。您可以在任何端口上运行http服务器。确保端口号大于1024。默认端口号为8000。

您可以按如下方式使用http.server。

首先,导航到所需目录并运行以下命令:

student@ubuntu:~/Desktop$ python3 -m http.server 9000

现在打开浏览器,在地址栏中写上localhost:9000,然后按回车。您将获得以下输出:

student@ubuntu:~/Desktop$ python3 -m http.server 9000 Serving HTTP on 0.0.0.0 port 9000 (http://0.0.0.0:9000/) ... 127.0.0.1 - - [23/Nov/2018 16:08:14] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:14] "GET /Downloads/ HTTP/1.1" 404 - 127.0.0.1 - - [23/Nov/2018 16:08:14] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:14] "GET /favicon.ico HTTP/1.1" 404 - 127.0.0.1 - - [23/Nov/2018 16:08:21] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [23/Nov/2018 16:08:21] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:21] "GET /favicon.ico HTTP/1.1" 404 - 127.0.0.1 - - [23/Nov/2018 16:08:26] "GET /hello/ HTTP/1.1" 200 - 127.0.0.1 - - [23/Nov/2018 16:08:26] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:26] "GET /favicon.ico HTTP/1.1" 404 - 127.0.0.1 - - [23/Nov/2018 16:08:27] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:27] "GET /favicon.ico HTTP/1.1" 404 -

ftplib 模块

ftplib是 Python 中的一个模块,提供通过 FTP 协议执行各种操作所需的所有功能。ftplib包含 FTP 客户端类,以及一些助手函数。使用此模块,我们可以轻松连接到 FTP 服务器以检索多个文件并对其进行处理。通过导入ftplib模块,我们可以使用它提供的所有功能。

在本节中,我们将介绍如何使用ftplib模块进行 FTP 传输。我们将看到各种 FTP 对象。

下载文件

在本节中,我们将学习如何使用ftplib从另一台机器下载文件。为此,创建一个get_ftp_files.py脚本,并在其中写入以下内容:

import os
from ftplib import FTP ftp = FTP('your-ftp-domain-or-ip')
with ftp:
 ftp.login('your-username','your-password') ftp.cwd('/home/student/work/') files = ftp.nlst()
    print(files) # Print the files for file in files:
        if os.path.isfile(file): print("Downloading..." + file) ftp.retrbinary("RETR " + file ,open("/home/student/testing/" + file, 'wb').write) ftp.close()

按如下方式运行脚本:

student@ubuntu:~/work$ python3 get_ftp_files.py

您应该获得以下输出:

Downloading...hello Downloading...hello.c Downloading...sample.txt Downloading...strip_hello Downloading...test.py

在前面的示例中,我们使用ftplib模块从主机检索了多个文件。首先,我们提到了另一台机器的 IP 地址、用户名和密码。为了从主机获取所有文件,我们使用了ftp.nlst()功能,为了将这些文件下载到我们的计算机,我们使用了ftp.retrbinary()功能。

使用 getwelcome()获取欢迎消息:

一旦建立了初始连接,服务器通常会返回欢迎消息。此消息通过getwelcome()功能发出,有时包含可能与用户相关的免责声明或有用信息。

现在我们将看到一个getwelcome()的示例。创建一个get_welcome_msg.py脚本,并在其中写入以下内容:

from ftplib import FTP ftp = FTP('your-ftp-domain-or-ip') ftp.login('your-username','your-password') welcome_msg = ftp.getwelcome() print(welcome_msg) ftp.close()

按如下方式运行脚本:

student@ubuntu:~/work$ python3 get_welcome_msg.py 220 (vsFTPd 3.0.3)

在前面的代码中,我们首先提到了另一台机器的 IP 地址、用户名和密码。在建立初始连接后,我们使用getwelcome()函数获取信息。

使用 sendcmd()函数向服务器发送命令

在本节中,我们将学习sendcmd()函数。我们可以使用sendcmd()函数向服务器发送一个简单的string命令,以获得字符串响应。客户端可以发送 FTP 命令,如STAT、PWD、RETR、STOR等。ftplib模块有多种方法可以包装这些命令。可以使用sendcmd()或voidcmd()方法发送命令。例如,我们将发送一个STAT命令来检查服务器的状态。

创建一个send_command.py脚本,并在其中写入以下内容:

from ftplib import FTP ftp = FTP('your-ftp-domain-or-ip') ftp.login('your-username','your-password') ftp.cwd('/home/student/') s_cmd_stat = ftp.sendcmd('STAT') print(s_cmd_stat) print() s_cmd_pwd = ftp.sendcmd('PWD') print(s_cmd_pwd) print() ftp.close()

按如下方式运行脚本:

student@ubuntu:~/work$ python3 send_command.py

您将获得以下输出:

211-FTP server status:
 Connected to ::ffff:192.168.2.109 Logged in as student TYPE: ASCII No session bandwidth limit Session timeout in seconds is 300 Control connection is plain text Data connections will be plain text At session startup, client count was 1 vsFTPd 3.0.3 - secure, fast, stable 211 End of status
257 "/home/student" is the current directory

在前面的代码中,我们首先提到了另一台机器的 IP 地址、用户名和密码。接下来,我们使用sendcmd()方法向另一台机器发送STAT命令。然后,我们使用sendcmd()作为PWD命令。

urllib 包

与http一样,urllib也是一个包,其中包含用于处理 URL 的各种模块。urllib模块允许您通过脚本访问多个网站。我们还可以使用这个模块下载数据、解析数据、修改头等等。

urllib有几个不同的模块,如下所示:

  • urllib.request:用于打开和读取 URL。
  • urllib.error:包含urllib.request引发的异常。
  • urllib.parse:用于解析 URL。
  • urllib.robotparser:用于解析robots.txt文件。

在本节中,我们将学习如何使用urllib打开 URL,以及如何从 URL 读取html文件。我们将看到一个使用urllib的简单示例。我们将导入urllib.requests。然后我们将 URL 的开头分配给一个变量,然后我们将使用一个.read()命令从 URL 读取数据

创建一个url_requests_example.py脚本,并在其中写入以下内容:

import urllib.request x = urllib.request.urlopen('https://www.imdb.com/') print(x.read())

按如下方式运行脚本:

student@ubuntu:~/work$ python3 url_requests_example.py

以下是输出:

b'\n\n<!DOCTYPE html>\n<html\n    xmlns:og="http://ogp.me/ns#"\n    xmlns:fb="http://www.facebook.com/2008/fbml">\n    <head>\n         \n        <meta charset="utf-8">\n        <meta http-equiv="X-UA-Compatible" content="IE=edge">\n\n    \n    \n    \n\n    \n    \n    \n\n    <meta name="apple-itunes-app" content="app-id=342792525, app-argument=imdb:///?src=mdot">\n\n\n\n        <script type="text/javascript">var IMDbTimer={starttime: new Date().getTime(),pt:\'java\'};</script>\n\n<script>\n    if (typeof uet == \'function\') {\n      uet("bb", "LoadTitle", {wb: 1});\n    }\n</script>\n  <script>(function(t){ (t.events = t.events || {})["csm_head_pre_title"] = new Date().getTime(); })(IMDbTimer);</script>\n        <title>IMDb - Movies, TV and Celebrities - IMDb</title>\n  <script>(function(t){ (t.events = t.events || {})["csm_head_post_title"] = new Date().getTime(); })(IMDbTimer);</script>\n<script>\n    if (typeof uet == \'function\') {\n      uet("be", "LoadTitle", {wb: 1});\n    }\n</script>\n<script>\n    if (typeof uex == \'function\') {\n      uex("ld", "LoadTitle", {wb: 1});\n    }\n</script>\n\n        <link rel="canonical" href="https://www.imdb.com/" />\n        <meta property="og:url" content="http://www.imdb.com/" />\n        <link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.imdb.com/">\n\n<script>\n    if (typeof uet == \'function\') {\n      uet("bb", "LoadIcons", {wb: 1});\n    }\n</script>\n  <script>(function(t){ (t.events = t.events || {})["csm_head_pre_icon"] = new Date().getTime(); })(IMDbTimer);</script>\n        <link href="https://m.media-amazon.cimg/G/01/imimg/safari-favicon-517611381._CB483525257_.svg" mask rel="icon" sizes="any">\n        <link rel="icon" type="image/ico" href="https://m.media-amazon.cimg/G/01/imimg/favicon-2165806970._CB470047330_.ico" />\n        <meta name="theme-color" content="#000000" />\n        <link rel="shortcut icon" type="image/x-icon" href="https://m.media-amazon.cimg/G/01/imimg/desktop-favicon-2165806970._CB484110913_.ico" />\n        <link href="https://m.media-amazon.cimg/G/01/imimg/mobile/apple-touch-icon-web-4151659188._CB483525313_.png" rel="apple-touch-icon"> \n

在前面的示例中,我们使用了返回字节数组的read()方法。这将以非人类可读的格式打印Imdb主页返回的 HTML 数据,但我们可以使用 HTML 解析器从中提取一些有用的信息。

Python urllib 响应头

我们可以通过调用响应对象上的info()函数来获取响应头。这将返回一个字典,因此我们还可以从响应中提取特定的头数据。创建一个url_response_header.py脚本,并在其中写入以下内容:

import urllib.request x = urllib.request.urlopen('https://www.imdb.com/') print(x.info())

按如下方式运行脚本:

student@ubuntu:~/work$ python3 url_response_header.py

以下是输出:

Server: Server Date: Fri, 23 Nov 2018 11:22:48 GMT Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Connection: close X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self' imdb.com *.imdb.com *.media-imdb.com withoutabox.com *.withoutabox.com amazon.com *.amazon.com amazon.co.uk *.amazon.co.uk amazon.de *.amazon.de translate.google.com images.google.com www.google.com www.google.co.uk search.aol.com bing.com www.bing.com Content-Language: en-US Set-Cookie: uu=BCYsJu-IKhmmXuZWHgogzgofKfB8CXXLkNXdfKrrvsCP-RkcSn29epJviE8uRML4Xl4E7Iw9V09w%0D%0Anl3qKv1bEVJ-hHWVeDFH6BF8j_MMf8pdVA2NWzguWQ2XbKvDXFa_rK1ymzWc-Q35RCk_Z6jTj-Mk%0D%0AlEMrKkFyxbDYxLMe4hSjUo7NGrmV61LY3Aohaq7zE-ZE8a6DhgdlcLfXsILNXTkv7L3hvbxmr4An%0D%0Af73atPNPOgyLTB2S615MnlZ3QpOeNH6E2fElDYXZnsIFEAb9FW2XfQ%0D%0A; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 14:36:55 GMT; Path=/; Secure Set-Cookie: session-id=000-0000000-0000000; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 14:36:55 GMT; Path=/; Secure Set-Cookie: session-id-time=2173692168; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 14:36:55 GMT; Path=/; Secure Vary: Accept-Encoding,X-Amzn-CDN-Cache,User-Agent x-amz-rid: GJDGQQTNA4MH7S3KJJKV

总结

在本章中,我们学习了用于双向客户机-服务器通信的套接字。我们学习了三个互联网模块:http、ftplib和urllib。http包中分别有用于客户端和服务器的模块:http.client和http.server。使用ftplib,我们从另一台机器下载了文件。我们还查看了欢迎信息和发送send命令。

在下一章中,我们将介绍构建和发送电子邮件。我们将学习信息格式和添加多媒体内容。此外,我们还将学习 SMTP、POP 和 IMAP 服务器。

问题

  1. 什么是套接字编程?
  2. 什么是 RPC?
  3. 导入到用户定义模块或文件的不同方式有哪些?
  4. 列表和元组之间有什么区别?
  5. 我们能在字典里找到重复的键吗?
  6. urllib、urllib2和requests模块之间有什么区别?

进一步阅读