python 应用 --3. 网络

一、网络介绍

1. 网络通信概述

网络通信:就是为了联通多方然后进行通信用的,即把数据从一方传递给另外一方。
使用网络能够把多方链接在一起,然后可以进行数据传递。
所谓的网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信。

2.IP 地址

数据机和交换机的功能后面会介绍。
IP 地址分类:

A 类

地址范围:1.0.0.1-126.255.255.254
默认子网掩码:255.0.0.0 或 0xFF000000
一般用于大型网络。

B 类

地址范围:128.1.0.1-191.255.255.254
默认子网掩码:255.255.0.0
一般用于中等规模网络。

C 类

地址范围:192.0.1.1-223.255.255.254
子网掩码:255.255.255.0
一般用于小型网络。
假设某个小型网的网络号是 192.168.33
则可以容纳 254 台电脑,192.168.33.1-192.168.33.255

D 类

地址范围:224.0.0.1-239.255.255.254
一般用于多路广播用户。
单播、广播、多播

E 类

以 “1111” 开始,为将来使用保留
E 类地址保留,仅作实验和开发用

私有 IP

在这么多网络 IP 中,国际规定有一部分 IP 地址是用于我们的局域网使用,也就
是属于私网 IP,不在公网中使用的,它们的范围是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255

注释

IP 地址 127.0.0.1~127.255.255.255 用于回路测试,
如:127.0.0.1 可以代表本机 IP 地址,用 http://127.0.0.1 就可以测试本机中配置的 Web 服务器。
例如:ping 127.0.0.1 来测试本机 TCP/IP 是否正常,
http://127.0.0.1:8080 等效于 http://localhost:8080

3.Linux、windows 查看网卡信息

windows

(1) 透过图形界面
搜索控制面板 -> 网络和 Internet-> 以太网 -> 详细信息 -> 描述行信息
(2) 命令行
win + R: 打开运行
输入 cmd
输入指令:ipconfig

linux

输入指令:ifconfig
ens40 的 ip 是对外通信用的,lo 是本地测试用的
关闭网卡:ifconfig ens40 down
ctrl+A:鼠标快速回到行首
ctrl+E:鼠标快速回到行末
开启网卡:ifconfig ens40 up

4. 端口

IP 用于区分不同的电脑,端口用于一台电脑内的不同进程 (进程是运行起来的程序)。

端口是怎么分配的:

(1) 知名端口
知名端口是众所周知的端口号,范围从 0 到 1023
例如:80 端口分配给 HTTP 服务,21 端口分配给 FTP 服务
一般情况下,如果一个程序需要使用知名端口的需要有 root 权限。
(2) 动态端口
动态端口的范围是从 1024 到 65535
之所以称为动态端口,是因为它一般不固定分配某种服务,而是动态分配。
动态分配是指当一个系统程序或应用程序程序需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配一个供它使用。当这个程序关闭时,同时也就释放了所占用的端口号。
端口并不是一一对应的。比如你的电脑作为客户机访问一台 WWW 服务器时,WWW 服务器使用 “80” 端口与你的电脑通信,但你的电脑则可能使用 “3457” 这样的端口。

怎样查看端口 ?

(1) windows 中使用 netstat -an 查看端口状态
-a 显示所有连线 (active connection) 以及接听连接端口 (listen port)
-n 以数字形式显示地址与连接端口号
(2) linux 中使用 netstat -an 查看端口状态
-a (all) 显示所有连线中的 Socket
-n (numeric) 直接使用 IP 地址,而不通过域名服务器。
(3) linux 中使用 lsof 检查监听端口
lsof(list open files)是一个列出当前系统打开文件的工具。

1
sudo lsof -nP -iTCP -sTCP:LISTEN
-n 不要将端口号转换为端口名称
-p 不解析主机名,显示数字地址
要查找正在侦听特定端口(例如端口 3306)的进程,可以使用:
1
sudo lsof -nP -iTCP:3306 -sTCP:LISTEN
参考:如何在 Linux 中检查侦听端口(正在使用的端口)

5.Socket 简介

socket (简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信。我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页、QQ 聊天、收发 email 等等。

套接字使用流程与文件的使用流程很类似:

(1) 创建套接字
(2) 使用套接字收 / 发数据
(3) 关闭套接字

Python 编程

在 Python 中使用 socket 模块的函数 socket 就可以完成:

python
1
2
3
4
import socket
socket.socket (AddressFamily, Type)
# ... 这里是使用套接字的功能(省略)...
s.close ()
说明:
函数 socket.socket 创建一个 socket,该函数带有两个参数:
(1) Address Family:可以选择 AF_INET(用于 Internet 进程间通信)或者 AF_UNIX(用于同一台机器进程间通信), 实际工作中常用 AF_INET
(2) Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)

二、UDP 网络编程

发送数据的流程

(1) 创建套接字
(2) 发送数据
(3) 关闭

接收数据的流程

(1) 创建套接字
(2) 绑定本机的信息 (IP 和 port)
(3) 接收数据
(4) 关闭

python
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
37
38
39
40
41
42
#coding=utf-8
from socket import *

def main ():
# 1. 创建 udp 套接字
udp_socket = socket (AF_INET, SOCK_DGRAM)

# 2. 准备接收方的地址
# '192.168.1.103' 表示目的 ip 地址
# 8080 表示目的端口
dest_addr = ('192.168.1.103', 8080) # 注意 是元组,ip 是字符串,端口是数字

# 3. 从键盘获取数据
send_data = input (" 请输入要发送的数据:")

# 4. 发送数据到指定的电脑上的指定程序中
udp_socket.sendto (send_data.encode ('utf-8'), dest_addr)
# udp_socket.sendto (b"hahaha", ("192.168.33.53", 8080))
# utf-8:一种编码格式,支持全球的语言都有一个唯一的标记

# 5. 绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
local_addr = ('', 7788)
# ip 地址和端口号,ip 一般不用写,表示本机的任何一个 ip,只能绑定本地的 IP
udp_socket.bind (local_addr)

# 6. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom (1024) # 1024 表示本次接收的最大字节数

# 7. 显示对方发送的数据
# 接收到的数据 recv_data 是一个元组
# 第 1 个元素是对方发送的数据
# 第 2 个元素是对方的 ip 和端口
print (recv_data [0].decode ('gbk')) # window 默认的编码是 gbk,英文不用编码
print (recv_data [1])
# print ("% s:% s" %(str (send_addr), rect_msg.decode ("gbk")) )
# recv_data 是一个元组 (接收到的数据,(发送方的 IP, 发送方的端口号))

# 8. 关闭套接字
udp_socket.close ()

if __name__ == "__main__":
main ()

问题 1

python
1
udp_socket.sendto (b"hahaha", ("192.168.33.53", 8080))

在字符串前面加上 b 可以转换成字节

问题 2

结果:Network is unreachable,可以使用 ping 测试网路连接状态,真的无法连线。
因为双方不是在同一个网段内(看 IP 地址)。
Q:怎么解决? A:网络连接改成桥接模式。
使用 sudo dhclient,等待分配 IP

问题 3

如果报这个错,代表程序是用 python2 写的,而且有中文,所以要加上 #coding=utf-8
vim 编辑器编辑模式下,ctrl+N 可以自动补全

聊天室实现

python
1
2
3
4
5
6
7
while true
send_data = input (" 请输入要发送的数据:")

if send_data == "exit":
break

udp_socket.sendto (send_data.encode ('utf-8'), dest_addr)

接收

如果一个程序运行起来,没有一个固定的端口,你是没办法给它发数据的。
当重新运行时,如果没有确定到底用哪个,系统默认会随机分配。
一般情况下,在一台电脑上运行的网络程序有很多,为了不与其他的网络程序占用同一个端口号,往往在编程中,udp 的端口号一般不绑定。但是如果需要做成一个服务器端的程序的话,是需要绑定的。

注释

python3 file: 用 python3 运行 xxx.py
python3: 打开 python3 的交互模式,用来验证某些知识点
ipython3: 比 python3 交互模式高端的一种交互模式