网络编程(王铭东老师)笔记
网络编程的目的
1.将多个设备通过网络进行连接在一起,可以将数据共享。
基础知识-01-ip地址
1.引入
为了能够确定网络数据收发双方是哪台电脑,需要用ip来标记电脑。
2.什么是地址
地址就是用来标记地点的
3.ip地址的作用
作用:在逻辑上标记一台电脑(唯一标记)
特点:不能的重复的。
基础知识-02-通过ip地址来理解通信的过程
1.课件中的图片
2.老师绘制的网络发送信息示意图
基础知识-03-IPv4以及IPv6
4.ip地址的分类(了解)
基础知识-04-IPv4的5种类别以及公有ip、私有ip
3.1 A类IP地址
一个A类IP地址由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”。
地址范围1.0.0.1-126.255.255.254
二进制表示为:00000001 00000000 00000000 00000001-01111110 11111111 11111111 11111110可用的A类网络有126个,每个网络能容纳1677214个主机。
3.2 B类IP地址
一个B类IP地址由2个字节的网络地址和2个字节的主机地址组成,网络地址的最高位必须是“10”,地址范围128.1.0.1-191.255.255.254
二进制表示为:10000000 00000001 00000000 00000001-10111111 11111111 11111111 11111110可用的B类网络有16384个,每个网络能容纳65534主机。
3.3 C类IP地址
一个C类IP地址由3字节的网络地址和1字节的主机地址组成,网络地址的最高位必须是“110范围192.0.1.1-223.255.255.254
二进制表示为: 11000000 00000000 00000001 00000001-11011111 11111111 11111110 11111110C类网络可达2097152个,每个网络能容纳254个主机
3.4 D类地址用于多点广播
D类IP地址第一个字节以“1110”开始,它是一个专门保留的地址。它并不指向特定的网络,目前这一类地址被用在多点广播(Multicast)中多点广播地址用来一次寻址一组计算机地址范围224.0.0.1-239.255.255.254
3.5 E类IP地址
以“1111”开始,为将来使用保留E类地址保留,仅作实验和开发用
3.6 私有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
基础知识-05-特殊的地址127.0.0.01
3.7 注意
IP地址127·0·0·1~127·255-255·255用于回路测试如:127.0.0.1可以代表本机IP地址,用 http://127.0.0.1 就可以测试本机中配置的Web服务器
基础知识-06-端口
1.引入
和地址用来标记一台电脑,为了能够标记电脑上运行中的程序,需要使用端口来标记。
2.什么是端口
端口就好一个房子的门,是出入这间厉子的必经之路。
注:进程是指正在运行的程序。
如果一个在运行中的程序需要收发网络数据。那么就需要有这样的端。
在linux系统中,端口可以有65536(2的16次方)个之多!
既然有这么多,操作系统为了统一管理,所以进行了编号,这就是端口号。
3.端口号
端口是通过端口号来标记的,端口号只有整数,范国是从0到65535
注意:
端口数可能由于不一样的*nix系统,可能不一样。
4.端口是怎样分配的
端口号不是随意使用的,而是按照一定的规定进行分配。端口的分类标准有好几种,我们这里不做详细讲解,只介绍一下知名端口和动态端口。
4.1知名端口(Well Known Ports)
知名端口是众所周知的端口号,范国从0到1023
21端口分配给FTP服务
22端口分配给SSH服多
80端口分配给HTTP服务
可以理解为,一些常用的功能使用的号码是估计的,好比电话号码110、10086、10010一样
一般情况下,如果一个程序需要使用知名端口的需要有root权限。
4.2动态端口 (Dynamic Ports)
动态端口的范围是从1024到65535。
之所以称为动态端口,是因为它一般不固定分配某种服务,而是动态分配。动态分配是指当一个系统程序或应用程序程序需要网络通信时,它向主机申请一个口,主机从可用的端口号中分配一个供它使用。
当这个程序关闭时,同时也就释放了所占用的端口号。
4.3 怎样查看端口 ?
用“netstat -an"查看端口状态
lsof -i [tcp/udp]:2425
5.小总结
我们知道,一台拥有IP地址的主机可以提供许多服务,比如HTTP(万维网服务)、FTP(文件传输)SMTP(电子郎件)等,这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系。实际上是通过”IP地址+端口号"来区分不同的服务的。
需要注意的是,端口并不是一一对应的。比如你的电脑作为客户机访问一台WWW服务器时,WWW服务器使用“80”端口与你的电脑通信,但你的电脑则可能使用“3457”这样的端口"
基础知识-07-使用netstat查看当前的端口的信息
在乌班图中查找。
UDP-01-使用udp发送数据
1.引入
程序如果想通过网络进行收发数据,需要使用socket进行编程来实现。
2.不同电脑上程序之间如何通信
UDP和TCP的区别
为了能够完成2台电脑(可以更多)上程序之间通信,需要有几个条件:
1.明确是哪台电脑到哪台电脑,即用ip地址来标记
2.明确电脑上的那个程序,即用端口来标记
3.还要明确怎样进行传送数据,即网络协议(可以俗的理解为怎样发送敔据,怎样接收数据的规范)
3.什么是socket
socket(简称 容接字)是进程(就是运行中的程序)间通信的一种方式,它与其他进程间通信的一个主要不周是:
它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 socket 来完成通信的例如: 我们每天浏览网页、QQ 聊天、收发 emai 等等。
4.创建socket
在 Python 中 使用socket 模块的socket 函数就可以完成。
impart socket
socket.sacket(AddressFamily, Type)
说明:
函数 socket.socket 创建一个套接字,该的数带有两个参数:
Address family:可以选择 AF_INET(用于Internet进程间通信)或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用 AFINET
Type :套接字类型,可以是S0CK_STREAM(流式套接字,主要用于TCP 协议)或者S0CK_DGRAM (数据报套接字,主要用于UDP 协议)
4.1创建一个 tcp socket(tcp套接字)
import socket
# 创建UPD的套接字
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 这就是使用套接字的功能,省略...
# 不用的时候,关闭套接字
s.close()
4.2创建一个 udp socket (udp套接字)
import socket
# 创建UPD的套接字
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 这就是使用套接字的功能,省略...
# 不用的时候,关闭套接字
s.close()
4.3 说明
套接字使用流程 与 文件的使用流程彼类似
1.创建套接字
2.使用套接字收/发数据
3.关闭套接字
UDP-02-遇到的问题说明
UDP-03-接收udp数据的程序
UDP-04-遇到的问题说明2
UDP-05-recvfrom的堵塞及端口变化的特点
UDP网络程序-发送、接收数据
1.UDP网络程序-发送数据
创建一个udp的网络程序流程很简单,具体步骤如下:
1.创建客户端套接字
2.发送/接收数据
3.关闭套接字
代码如下:
# coding=utf-8from socket import *# 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)# 5. 关闭套接字
udp_socket.close()
运行现象:
在Ubuntu中运行脚本:
在windows中运行“网络调试助手”:
2. UDP网络程序-发送、接收数据
#coding=utf-8from socket import *# 1. 创建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)# 2. 准备接收方的地址
dest_addr = ('192.168.236.129', 8080)# 3. 从键盘获取数据
send_data = input("请输入要发送的数据:")# 4. 发送数据到指定的电脑上
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)# 5. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数# 6. 显示对方发送的数据
# 接收到的数据recv_data是一个元组
# 第1个元素是对方发送的数据
# 第2个元素是对方的ip和端口
print(recv_data[0].decode('gbk'))
print(recv_data[1])# 7. 关闭套接字
udp_socket.close()
python脚本:
网络调试助手截图:
PREVIOUS
UDP-06-编码:str与bytes之间的转换
1. 引入
python3中使用套接字发送数据时,要求使用bytes类型的数据,因此就用到了编码转换
2. 不同数据类型编码的方式
str->bytes:encode编码
bytes->str:decode解码
字符串通过编码成为字节码,字节码通过解码成为字符串。
>>> text = '我是文本'
>>> text
'我是文本'
>>> print(text)
我是文本
>>> bytesText = text.encode()
>>> bytesText
b'\xe6\x88\x91\xe6\x98\xaf\xe6\x96\x87\xe6\x9c\xac'
>>> print(bytesText)
b'\xe6\x88\x91\xe6\x98\xaf\xe6\x96\x87\xe6\x9c\xac'
>>> type(text)
<class 'str'>
>>> type(bytesText)
<class 'bytes'>
>>> textDecode = bytesText.decode()
>>> textDecode
'我是文本'
>>> print(textDecode)
我是文本
复制Error复制成功...
其中decode()与encode()方法可以接受参数,其声明分别为:
bytes.decode(encoding="utf-8", errors="strict")
str.encode(encoding="utf-8", errors="strict")
复制Error复制成功...
其中的encoding是指在解码编码过程中使用的编码(此处指“编码方案”是名词),errors是指错误的处理方案。
详细的可以参照官方文档:
- str.encode()
- bytes.decode()
UDP-07-bind(绑定)本地信息
1. 引入
如果一个网络程序需要接收数据,那么就需要一个明确的端口,此时就用到“绑定”
2. udp网络程序-端口问题
会变的端口号
重新运行多次脚本,然后在“网络调试助手”中,看到的现象如下:
说明:
- 每重新运行一次网络程序,上图中红圈中的数字,不一样的原因在于,这个数字标识这个网络程序,当重新运行时,如果没有确定到底用哪个,系统默认会随机分配
- 记住一点:网络程序在运行的过程中,通过端口能够标识这个程序,所以如果其他电脑上的网络程序如果想要向此程序发送数据,那么就需要向这个数字(即端口)标识的程序发送即可
3. UDP绑定信息
3.1 为什么要绑定
一般情况下,在一台电脑上运行的网络程序有很多,为了不与其他的网络程序占用同一个端口号,往往在编程中,udp的端口号一般不绑定
但是如果需要做成一个服务器端的程序的话,是需要绑定的,想想看这又是为什么呢?
如果报警电话每天都在变,想必世界就会乱了,所以一般服务性的程序,往往需要一个固定的端口号,这就是所谓的端口绑定
# coding=utf-8from socket import *# 1. 创建套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)# 2. 绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
local_addr = ('', 7788) # ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udp_socket.bind(local_addr)# 3. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数# 4. 显示接收到的数据
print(recv_data[0].decode('gbk'))# 5. 关闭套接字
udp_socket.close()
运行结果:
4. 注意点
如果当前使用的这个udp端口正在使用中,如果此时有另外一个程序也是用的这个端口,那么就会出现“端口被占用”的问题
先运行一个程序,让其一直占用7788端口
然后再运行一个程序,让其也绑定这个端口,此时就会出现问题
5. 小总结
- 一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行此程序端口可能会发生变化
- 一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是给此进程的
3.2 绑定示例
UDP-08-绑定时的注意点1
老师小结
1.ip地址是本机电脑中的ip
(1)如果要是手动写上当前电脑的ip,可行,但是又个问题:如果重启电脑之后当前电脑的ip如果变了,那么这个程序中绑定的那个ip就需要修改,麻烦。
(2)一般来说,让python程序自动选择当前电脑的ip是一个很好的解决方案。当前电脑的ip是什么,那么就给这个程序绑定什么,一句话:自动识别然后绑定。
2.端口
(1)不能随便的绑定1-1023之间的端口。因为他们是知名端口号,不能随便使用,一般用来特殊的用途,例如22专门用来ssh远程连接使用的。
(2)如果当前的某个端口正在使用中,也不能绑定。在1024~65535端口号之间,如果这个端口正在被其他的程序使用,那么就不能再次绑定,除非刚刚用这个端口的程序结束。否则只能换端口号。
UDP-09-绑定的最核心原因
最核心的原因:如果要使用udp做一个服务的程序,那么这个程序应该先运行,并且需要一个明确的端口号,否则其他程序不能够把需要的请求数据发送给这个服务方的电脑 。
UDP-10-绑定时的注意点2
UDP-11-理解网络通信的基本过程
网络通信过程(简单版)
1. 引入
为了能够对网络过程的来龙去脉搞清楚,需要认真思考通信的过程
2. 通信过程简单版
2.1 生活中的过程
2.2 程序中的过程
将接收数据的代码放入循环中,运行代码时可以一直接收数据。将发送数据的代码放置循环中的作用是一样的,也可以反复发送数据。
服务器代码:
import socket
# 1.创建socket对象
chatSocket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 2.设置并绑定端口
chatAdress=("",8000)
chatSocket.bind(chatAdress)
# 3.接收数据
while True:recvContent=chatSocket.recvfrom(1024)print(recvContent[0].decode("utf-8"))
# 4.关闭
chatSocket.close()
发送数据老师用的是网络调试助手(mNetAssist),自己下载不到,只能发编写了一段发送数据代码来代替(放置在两个不同的文件夹中),代码如下:
import socket
# 1.创建socket对象
c=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 2.设置并绑定端口
selfAdress=("",8899)
c.bind(selfAdress)
# 2.发送数据
while True:sendContent=input("请输入顾客排队序号:").encode('utf-8')aimAdress=("192.168.43.152",8000)c.sendto(sendContent,aimAdress)
# 3.关闭
c.close()
2.3 通过目的端口区分给哪个程序
- 接收方首先会判断接收到的数据目的ip是否是本电脑的ip,如果是则进行处理,否则扔掉
- 根据提取数据的目的端口以及使用的协议(udp、tcp),判断电脑中是否有此端口对应的程序,如果有则传递给这个程序,否则扔掉数据
- 应用程序接收到数据,然后显示
3. 小总结
网络通信过程中之所需要ip、port等,就是为了能够将一个复杂的通信过程进行任务拆分为一个一个具体的任务,然后相互配合,从而保证数据准确无误的传递
UDP-12-案例:UDP聊天室
1.想法来源
去银行办理相关业务时,一般会先取号,然后等待叫号即可,如下圈所示·那么能否用python来写一个程序,模拟当前叫号显示牌呢?
老师说他的很多想法都来源于生活。
2.需求分析
1.需要用一个程序先运行
2.让这个程序一直等待接收 其他 程序发送过来的数据
3.接收数据之后显示出来
3.代码实现
UDP-13-案例:UDP聊天软件1
UDP-14-案例:UDP聊天软件2
广播-01-UDP广播
广播
1. 引入
思考一个问题:
假如在我们现在的教室局域网(192.168.14.x)中,如果想给其他所有电脑上的2425端口发送一个相同的数据,改怎样做呢?
你可能会这样做:
写一个程序,使用循环的方式向192.168.14.1一直到192.168.14.254这个范围的所有电脑上的2425端口 发送一次数据即可。
这样做能实现,但是效率非常低,因为需要将这个数据发送254次,如果换到了B类的局域网中那么就需要发送65534次,显然这么做是不太恰当的
那该怎样做?
要是能发送一次数据,这个数据会被所有的电脑都接收,那就给力了,,,,恰巧接下来要讲解的UDP广播就能实现这个功能
2. 广播的作用
socket只需要发送1次UDP数据,就可以发送给本局域网中的任何一台电脑发送相同的数据
3. 使用UDP广播的流程
import socket# 1. 创建UDP套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 2. 设置UDP套接字允许其广播(注意如果udp套接字需要广播,则一定要添加此语句)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)# 选做 绑定本地信息
# s.bind(("", 8080))# 4. 向本局域网中发送广播数据
# 此时只要是本局域网中的电脑上有 用1060端口的udp程序 它就会收到此数据
dest_info = ("<broadcast>", 1060) # <broadcast>会自动改为本局域网的广播ip
s.sendto('hello world !'.encode('utf-8'), dest_info)# 5. 关闭套接字
s.close()
4. 小总结
如果需要用到广播,则需要对这个套接字进行设置,方式是很固定的,如下
套接字.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
但是要注意一点:真正用到广播那么就考虑添加这个设置,否则不要添加,因为这样会到这个局域网中会比较拥堵
广播-02-UDP广播注意点以及案例
广播-小案例
1.目的
用更有逾的效果,来体会广播的威力
2.功能效果描述
发送一个udp广播数据,发送一个 飞秋 消息给所有人
3.飞秋消息格式
#飞秋消息格式如下
#版本:消息序号:用户名:电脑名:功能(32表示发送消息):发送的消息内容
"1:123456789:莉莉:水果电脑:32:有时间么?"
4.参考代码
TCP-01-理解TCP
TCP简介
1. 引入
使用UDP发送数据容易丢失,而TCP能够保证数据稳定传送,所以更多时候用的是TCP,例如浏览器底层实现就是用的TCP
2. TCP介绍
TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的传输通信协议
3. TCP作用
通过TCP协议,能够更加稳定的将数据传递到目的地
4. 通俗理解TCP
4.1 先理解UDP
用一个收发信件的方式来理解
特点:
- 每封信件都要写 收件人的信息以及邮编等
- 发件人发送之后,收件人不需要一直等待,即在收到信之前,收件人可以做其他的事情
- 消息通过信件传送,丢失的可能性较高
最明显的一点:简单,但不稳定
说明:
- UDP发送数据时,只要明确对方的ip、port就能够将数据直接发送过去
- 当接收方收到数据之后,可以直接进行处理,不需要告知发送方数据已收到
4.2 再理解TCP
用一个打电话的方式来理解
打电话时,需要先拨号,然后再发送数据,而且有个特点,当你说了一句话之后 如果对方没有反应 你可能会问一问对方是否听到了你刚刚所说的话,等沟通结束后 双方挂断电话
特点:
- 先拨号,再说话、听
- 在电话沟通的过程中,不能与其他的人打电话
- 消息通过信件传送,丢失的可能性小
最明显的一点:复杂,但稳定
- TCP发送方首先要与TCP接收方之间建立连接(双方互相打招呼,分配好资源等)
- TCP发送方发送数据时,只需要填写数据内容即可,不需要再写目的ip、port等,因为之前的“连接”已经做好了准备
- TCP接收方收到数据之后,接收方的操作系统会自动回送一个“确实收到”的消息给发送方,这样做的目的是让发送方知道刚刚发送的数据对方已经成功的接收到
- 当数据收发完毕,双方再次互相打招呼,将各自的资源释放
5. TCP特点
5.1 面向连接
通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统资源,以管理连接的状态和连接上的传输。
双方间的数据传输都可以通过这一个连接进行。
完成数据交换后,双方必须断开此连接,以释放系统资源。
这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。
5.2 可靠传输
1)TCP采用“发送-应答”机制
TCP发送的每个数据都必须得到接收方的应答才认为这个TCP数据传输成功
2)超时重传
发送端发出一个数据之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个数据。
TCP为了保证不发生丢数据,就给每个数据一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的数据发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据就被假设为已丢失将会被进行重传。
3)错误校验
TCP用校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
- 流量控制和阻塞管理
流量控制用来避免主机发送得过快而使接收方来不及完全收下。
6. TCP与UDP的不同点
- 面向连接(确认有创建三方交握,连接已创建才作传输。)
- 有序数据传输
- 重发丢失的数据包
- 舍弃重复的数据包
- 无差错的数据传输
- 阻塞/流量控制