1. python的模块导入规则
参考
1.1 系统自带模块
系统自带的模块直接import导入
import time
import unittest
1.2 第三方下载模块
第三方下载模块也可以直接导入
import HTMLTestRunner
import requests
1.3 导入模块的部分函数或类
from time import sleep,strftime
from time import *
1.4 导入自己写的模块
- 同文件夹: 直接import模块名
- 跨文件夹: from [文件夹.文件夹.模块] import [类(或函数)]
例如自定义了2个加法如下:
# class01/myAdd2.pydef myAdd2(a, b):print("自定义加法2")return a + b
# class02/myAdd2.pydef myAdd1(a, b):print("自定义加法1")return a + b
在文件夹class01下面创建一个addTest文件测试导入自己的加法模块
from class01.myAdd2 import myAdd2
from class02.myAdd1 import myAdd1print(myAdd2(1,3))
print("*************")
print(myAdd1(2,4))
2. 网络 - udp
参考
2.1 网络通信概述
- 网络就是一种辅助双方或者多方能够连接在一起的工具
- 使用网络的目的:
- 联通多方进行通信,把数据从一方传递给另外一方
- 为了让不同电脑上运行的软件之间能够互相传递数据,就需要借助网络的功能
- 总的来说:
- 使用网络能够把多方链接在一起,然后可以进行数据传递
- 所谓网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信
2.2 ip地址(重点)
- 地址就是用来标记地点的
- ip地址: 用来在网络种标记一台电脑,比如: 192.168.1.1; 在本地局域网上是唯一的
- 每一个ip地址包括两部分: 网络地址和主机地址
2.2.1 A类ip地址
一个A类IP地址由1字节的网络地址和3字节的主机地址组成,网络地址的最高位必须是"0",
地址范围: 1.0.0.1 ~ 126.255.255.254
二进制表示为: 00000001 00000000 00000000 00000001 ~ 011111110 11111111 11111111 11111110
可用的A类网络有126个,每个网络能容纳 1677214个主机
2.2.2 B类ip地址
一个B类IP地址由两个字节的网络地址和2个字节的主机地址组成,网络地址的最高位必须是"10"
地址范围: 128.1.0.1 ~ 191.255.255.254
二进制表示位: 10000000 00000001 00000000 00000001 ~ 10111111 11111111 11111111 11111110
可用的B类网络由16384各,每个网络能容纳65534主机
2.2.3 C类ip地址
一个C类IP地址由3字节的网络地址和1字节的主机地址组成,网络地址的最高位必须是"110"
地址范围: 192.0.1.1 ~ 223.255.255.254
二进制表示位: 11000000 00000000 00000001 00000001 ~ 11011111 11111111 11111110 11111110
C类网络可达2097152各,每个网络能容纳254个主机
2.2.4 D类地址用于多点广播
d类ip地址第一个字节以"1110"开始,它是一个专门保留的地址
它并不指向特定的网络,目前这一地址被用在多点广播中
多点广播地址用来依次寻址一组计算机, 地址范围: 224.0.0.1 ~ 239.255.255.254
2.2.5 E类ip地址
以"1111"开头,位将来使用保留
E类地址保留,仅作实验和开发用
2.2.6 私有ip
这么多网络ip中,国际规定有一部分ip地址是给我们的局域网使用,也就是属于私网ip,不在公网中使用,它们的范围是:
10.0.0.0 ~ 10.255.255.255172.16.0.0 ~ 172.31.255.255192.168.0.0 ~ 192.168.255.255
2.2.7 注意
ip地址 127.0.0.1 ~ 127.255.255.255 用于回路测试
如: 127.0.0.1 可以代表本机ip地址, 用 http://127.0.0.1
就可以测试本机种配置的web服务器
2.3 Linux命令(ping、ipconfig等)
- 本地网卡 :又叫本地回环,用来测试电脑是否能够进行正常的网络通信.
- 在linux中查看网卡信息:
ifconfig
- 假设网卡的名字位 ens40,关闭该网卡:
sudo ifconfig ens40 down
- 打开该网卡:
sudo ifconfig ens40 up
- 假设网卡的名字位 ens40,关闭该网卡:
2.4 端口(重点)
- ip是区分主机用的,端口是区分同一个主机种不同进程用的
- 端口就好比一个房子的门,是出入这件房子的必经之路
- 如果一个程序需要收发网络数据,那么就需要这样的端口
- 操作系统为了统一管理,对其进行了编号,这就是
端口号
2.4.1 端口号
端口是通过端口号来标记的,端口号只有整数,范围是从0到65535
端口数不一样的*nix系统不一样,还可以手动修改
进程与程序: 一个程序在没有运行起来的时候叫进程,在运行起来之后叫程序
2.4.2端口是怎样分配的
端口号不是随意使用的,而是按照一定的规定进行分配
端口的分类标准有好几种,下面只介绍一下知名端口和动态端口
知名端口: 是众所周知的端口号,范围从 0 到 1023
80端口分配给HTTP服务
21端口分配给FTP服务
可以理解为,一些常用的功能使用的端口
动态端口: 范围从 1024 到 65535
之所以是动态端口, 是因为它一般不固定分配某种服务,而是动态分配
动态分配: 当一个系统程序或应用程序需要网络通信时,它向主机申请一个端口,主机从可用的端口号种分配一个供它使用,当这个程序关闭时,同时也就释放了所占用的端口号
2.4.3 小结
一台有ip的主机可以提供许多服务,比如HTTP、FTP、SMTP等,这些服务完全可以通过一个ip地址来实现。那么主机是怎么样区分不同的网络服务呢? 显然不能只靠ip地址,因为ip地址与网络服务的关系是一对多的关系。实际上是通过"ip + 端口号"来区分不同的服务的。
2.5 socket简介
2.5.1 不同电脑上的进程之间如何通信
首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!
在1台电脑上可以通过进程号(PID)来唯一标识一个进程,但是在网络种这是行不通的.
其实TCP/IP协议族已经帮我们解决了这个问题,网络层的"ip地址"可以唯一标识网络种的主机,而传输层的"协议+端口"可以唯一标识主机种的应用进程(进程)
这样利用"ip地址、协议、端口"就可以标识网络中的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互
注意:
- 所谓
进程
指的是: 运行的程序以及运行时用到的资源这个整体称为进程- 所谓
进程通信
指的是: 运行的程序之间的数据共享
2.5.2 什么是socket
socket(简称: 套接字
)是进程通信的一种方式,它与其他进程通信的一个主要不同是: 它能实现不同主机的进程间通信,我们网络上各种各样的服务大多是基于Socket来完成通信的.下面是在python中使用socket的代码
2.5.3 创建socket
在python中使用socket模块的函数socket就可以完成:
import socket
socket.socket(AddressFamily, Type)
说明:
函数 socket.socket创建一个socket,该函数带有两个参数:
- Address Family: 可以选择 AF_INET(用于internet进程间通信) 或者 AF_UNIX(同一台机器进程间通信),实际工作中常用AF_INET
- Type: 套接字类型,可以是 SOCK_STREAM(流式套接字, 主要用于 TCP协议)或者 SOCK_DGRAM(数据报套接字,主要用于UDP协议)
创建一个tcp socket(tcp套接字)
import socket# 创建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# ...这里是使用套接字的功能 (省略) ...# 不用的时候,关闭套接字
s.close()
创建一个udp socket(udp套接字)
import socket# 创建udp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# ...这里是使用套接字的而功能 (省略) ...# 不用的时候,关闭套接字
s.close()
说明:
- 套接字使用流程与文件的使用流程很类似
- 创建套接字
- 使用套接字 收/发 数据
- 关闭套接字
2.6 udp网络程序 - 发送、接受数据
2.6.1 使用socket发送upd数据
# 网络编程/01-socket的基本使用
import socketdef main():# 1.创建一个udp套接字udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 2. 准备接收方的地址# "192.168.1.103" 表示目的ip地址# 8080表示目的端口dest_addr = ("192.168.0.106", 8080) # 地址是元组, ip是字符串,端口是数字# 3. 从键盘获取数据send_data = input("请输入要发送的数据: ")# 4. 发送数据到指定的电脑上的指定程序中udp_socket.sendto(send_data.encode("utf-8"), dest_addr)# 5. 关闭套接字udp_socket.close()print("----------run----------")if __name__ == "__main__":main()
.encode
: 将前面的数据编码
【栗子】: 改写上面的栗子,变为可以循环发送
# 网络编程/03-socket的基本使用
import socketdef main():upd_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)while True:send_data = input("请输入要发送的数据(exit退出): ")# 如果输入的数据是 exit, 退出if send_data == "exit":breakelse:dest_addr = ("192.168.0.106", 8080)upd_socket.sendto(send_data.encode("utf-8"), dest_addr)upd_socket.close()if __name__ == "__main__":main()
2.6.2 使用socket接受udp数据
如果你的程序想收到数据,必须得有一个固定的端口,将会造成数据丢失.
下面提供了一个绑定端口的API
from socket import *def main():# 1. 创建套接字udp_socket = socket(AF_INET, SOCK_DGRAM)# 2. 绑定本地的相关信息,如果一个网络程序不绑定,则系统随机分配local_addr = ("192.168.0.106", 7788) # ip地址和端口号,ip一般不用写,表示本既的任何一个ipudp_socket.bind(local_addr)# 3. 等待接收方发送的数据recv_data = udp_socket.recvfrom(1024) # 表示本次接收的最大字节数# 4. 显示接收到的数据print(recv_data[0].decode('utf-8'))# 5. 关闭套接字udp_socket.close()if __name__ == "__main__":main()
2.7 upd绑定端口问题(重点)
2.7.1 在发送信息前绑定端口号
一般来说,在发送信息前,都会先绑定端口号,这样方便收到接收端的信息
from socket import *def main():udp_socket = socket(AF_INET, SOCK_DGRAM)# 给udp绑定一个端口号udp_socket.bind(("", 7890))while True:send_data = input("请输入要传输的数据: ")if send_data == "exit":breakelse:udp_socket.sendto(send_data.encode("utf-8"), ("192.168.0.106", 8080))udp_socket.close()if __name__ == "__main__":main()
在同一时刻,一个端口号只能绑定一个进程. 如果某一个端口被占用,其他的程序将无法使用该端口号
2.7.2 小结
1. 创建套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
2. 绑定端口号
udp_bind(("", 7890))
3. 使用套接字收发数据
# 发送数据
udp_socket.sendto("xxx".encode("gbk"), ("192.168.0.1",8080))# 接收数据
udp_socket.recvfrom(1024) # 1024 代表一次接收的大小
4. 关闭套接字
udp_socket.close()
测试用的工具: mNetAssist
2.8 案例: udp聊天器
说明:
- 在电脑上编写程序,需求如下:
- 获取键盘数据,并发送给对方
- 接受数据并显示
本地回环的使用:
如果你想在本地测试一下,数据在不同进程之间的通信,可以使用本地回环网卡, ip地址为 127.0.0.1. 它是固定不变的。注意本地回环,不能用于网络通信~
from socket import *def send_msg(udp_socket):# 1.获取键盘数据,并将其发送给对方msg = input("\n请输入要发送的数据: ")# 2. 输入对方的ip地址dest_ip = input("\n请输入对方的ip地址: ")# 3. 输入对方的portdest_port = int(input("\n请输入对方的port: "))# 4. 发送数据udp_socket.sendto(msg.encode("gbk"), (dest_ip, dest_port))def recv_msg(udp_socket):# 1. 接收数据recv_msg = udp_socket.recvfrom(1024)print(recv_msg[0].decode("gbk"))def main():udp_socket = socket(AF_INET, SOCK_DGRAM)send_msg(udp_socket)recv_msg(udp_socket)udp_socket.close()if __name__ == "__main__":main()
-
以上程序在数据发送成功之后,会进入一种阻塞状态(在此状态下该端口号下的进程不会做任何事,等待唤醒)
-
套接字是一个可以同时收发数据的,下面说说 单工、半双工、全双工的概念:
- 单工: 考虑收音机,只能收而不能发送信息
- 半双工: 考虑对讲机, 同一时刻只能发送或者接收信息.不能同时进行
- 全双工: 考虑打电话,可以同时进行收发信息(注意,套接字是全双工的~)
操作系统会先将某个端口的数据存在内存中,当有程序调用将进程的数据时,会从操作系统中拿到该端口下的数据