课后大总结
01-socket套接字基本流程
不论使用UPD协议还是TCP,其使用基本流程是一致的。
一、流程
1.创建套接字
2.使用套接字收/发数据
3.关闭套接字
二、示例代码
import socket
# 1.创建UPD的套接字
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
'''
第一个位置参数family:socket.AF_INET,不论是写UDP协议还是TCP协议都是一样的。
第一个位置参数type:使用UPD协议时为socket.SOCK_DGRAM,使用TCP协议时为socket.SOCK_STREAM
'''
# 2.使用套接字
'''
本步骤根据创建的socket用途不一样,而实现的代码也不一样,此处仅演示使用步骤,不写具体代码。
'''
# 3.不用的时候,关闭套接字
s.close()
02-UPD流程
笔记说明:
1.课后大总结中代码,均是结合老师所讲及自己的思考总结出来的。
2.UDP代码自己总结了三种情形:
(1)纯收/纯发。
(2)收发兼备。
(3)循环收发。
一、纯收/纯发UDP流程
创建python两个项目,一个项目名称为UPD_Server,另一个项目名称为UPD_Client。前者创建一个py文件serverSocket,将纯收服务器源码粘贴进去,后者创建一个py文件clientSocket,将纯发客户端源码粘贴进去。先运行服务,后运行客户端,即可实现数据发与收。该方法同样适用于TCP的学习和练习。
1.纯收服务器流程
(1)步骤
1.创建socket对象。 2.设置并绑定端口。服务器必须绑定ip和端口,否则,客户端无法为服务器发送数据。 3.接收数据。 4.关闭。
(2)代码
import socket
# 1.创建socket对象
serverSocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.设置并绑定端口
serverIPPort=("", 8000)
serverSocket.bind(serverIPPort)
# 3.接收数据
recvContent = serverSocket.recvfrom(1024)
print(recvContent)
# 4.关闭
serverSocket.close()
2.纯发客户端流程
(1)步骤
1.创建socket对象 2.发送数据 3.关闭socket对象
(2)代码
import socket
# 1.创建socket对象
clientSocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.发送数据
sendContent = 'Hello World'.encode('utf-8')
serverIPPort = ("192.168.43.152", 8000)
clientSocket.sendto(sendContent, serverIPPort)
# 3.关闭
clientSocket.close()
3.纯收服务器和纯发客户端流程区别
服务器必须绑定ip和端口,而客户端不需要(当然也可以绑定)。个人理解的原因是:服务器电脑在使用时,除操作系统外,服务器有可能只运行服务器软件一个程序,或者很少量的应用程序,运行时,其设置的端口不会与正在运行的另的程序端口产生冲突,导出无法运行。而个人电脑在使用时,运行的需要连网的软件比较多,占用端口也多,如果设置了端口,可能导致自己创建的客户端程序会与其他连网软件的端口产生冲突,导致无法运行。客户端如果不设置端口,则运行客户程序时,操作系统会自动为其随机分配一个端口,而不会影响其运行。
4.类方法解析
下述方法中的s表示一个udp协议的socket对象。
1.s.bind(adress)
s.bind(adress)
参数:Adress socket对象需要绑定的地址,其数据类型是一个元组。该元组包括两个元素,分别为ip和端口port,书写格式如下:Adress=(ip,port)如果将ip设置空字符串,则socket对象会自动获取当前电脑的ip地址
2.s.recvf(num)
s.recvf(num)参数:数值类型为int,表示一次接受多个字符的数据。比如传入1024,即
运行该方法时,一次可以接收客户端传过来的1024个字节的数据。该方法返回一个元组,该元组包含两个元素,第1个元素为二进制数据,第
二个元素为客户端的地址(包括ip和端口)。数据形式如下:1.客户端发的数据为英语字母或数据(b'Hello World', ('192.168.43.152', 64343))2.客户端发的数据包含非英语字母或非数据,比如发来的是汉字。(b'\xe4\xbd\xa0\xe5\xa5\xbd', ('192.168.43.152', 63976))
3.s.sendto(data,adress)
s.sendto(data,adress)参数:data,需要传入二进制数据,如果传入的不是二进制数据,则需要转换
成为二进制数据,否则会报错。比如,如果需要发送“Hello World”,则必须使用字
符的encode()方法将该字符串转换成为二进制数据。比如:"Hello World".encode("utf-8")参数:1.adress,该参数的函数同bind()方法中的参数adress含义相同。2.注意:客户端发送的字符串时encode()中编码参数与服务器收到字符串decode()中参数必须一至。
二、收发兼备的服务器和客户端
本段代码在纯收服务器和纯发客户端代码基础上升级而来。
1.服务器代码
import socket
# 1.创建socket对象
serverSocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.设置并绑定端口
serverIPPort=("", 8001)
serverSocket.bind(serverIPPort)
# 3.接收/数据
recvContent = serverSocket.recvfrom(1024)
# 4.发送数据
recvData,ClientIPPort=recvContent
print(recvData.decode('utf-8'))
inputText=input("请输入回复内容:").encode('utf-8')
serverSocket.sendto(inputText,ClientIPPort)
# 4.关闭
serverSocket.close()
2.客户端代码
import socket
# 1.创建socket对象
clientSocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.设置并绑定端口
clientIPPort=("", 8080)
clientSocket.bind(clientIPPort)
# 3.发送数据
sendContent = input("请输发送内容:").encode('utf-8')
serverIPPort = ("192.168.43.152", 8001)
clientSocket.sendto(sendContent, serverIPPort)
# 4.接收数据
recvData, _=recvContent=clientSocket.recvfrom(1024)
print(recvData.decode('utf-8'))
# 4.关闭
clientSocket.close()
3.开发畅想
(1)收发兼备的服务器和客户端流程基本一致。其步骤如下:
a.创建socket对象。
b.绑定地址。
c.发送/接收数据。
d.关闭socket对象。
(2)由于二者使用流程基本一致。二者唯一区别在数据使用上:服务器先收后发,而客户端发先后收。
(3)能否多线程,将收发功能融为一体,需要实现的需求及需要解决的问题如下:
a.收发同时运行(该功能多线程可以实现)。
b.使用线程和if语句,将服务器和客户端的流程整合成一致。这样开发一个程序,即可做服务器又可做客户端。这样就可以不用另外设置电脑做服务器或租用服务器了,可以大大降低开发成本。
c.为防止端口号别的软件冲突导致程序无法运行,可以设置一个输入框架,用户手动输入端口号,使用方法,使用时,收发双方只需要沟通一下,使用共同的端口号就可以实现聊天和文件收发。也可以实现保存聊天记录等功能,只需要将聊天记录以文件形式存于本地电脑即可。
另外一套解决方法。开发时设置一个默认的其他程序不常用的端口号。如果运行时,软件的端口号同其他软件冲突:提示用户有两个解决办法:
1.关闭运行的存在冲突端口号的程序。
2.提示用户设置新窗口号并告诉聊天的对象。
d.老师所说的C\S模式,感觉应是聊天双方使用的实际上都是客户端,发送的数据都会先发到服务上,然后服务再将数据转发给对方。这样,开发一个聊天软件,则多了一个服务器成本。
三、使用循环收发数据的服务器和客户端
1.服务器代码
import socket
# 1.创建socket对象
serverSocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.设置并绑定端口
serverAdress=("", 9999)
serverSocket.bind(serverAdress)
# 3.接收数据
while True:bytesData, _=serverSocket.recvfrom(1024)data=bytesData.decode("utf-8")if data=="退出":breakelse:print(data)
# 4.关闭
serverSocket.close()
2.客户端代码
import socket
# 1.创建socket对象
clientSocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.发送数据
serverAdress=("192.168.43.152", 9999)
while True:inputText=input("请输入发送信息(输入退出,则客户端关闭):")sendContent=inputText.encode("utf-8")clientSocket.sendto(sendContent, serverAdress)if inputText=="退出":break
# 3.关闭
clientSocket.close()
3.开发畅享
使用循环可以在UI界面中实现持续发送和接收数据,只需要将关闭窗口作为循环退出的条件即可。
如果加上线程,就可以使用循环,同时实现收和发功能。
03-TCP流程
一、纯收/纯发流程
1.服务器代码
import socket
# 1.创建socket套接字对象
serverSocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2.绑定ip和端口
serverIPPort=("127.0.0.1", 9000)
serverSocket.bind(serverIPPort)
# 3.设置服务器处于监听状态
serverSocket.listen(128)
# 4.等待客户端连接
clientSocket, clientAdress=serverSocket.accept()
# 5.接收数据
recvData=clientSocket.recv(1024)
print(recvData)
# 6.关闭服务器套接字socket
serverSocket.close()
2.客户端代码
import socket
# 1.创建socket对象
clientSocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.连接服务器
serverAdress=('127.0.0.1',9000)
clientSocket.connect(serverAdress)
# 3.发送数据
sentContent="Hello World".encode("utf-8")
clientSocket.send(sentContent)
# 4.关闭对象
clientSocket.close()
3.流程对比
(1)客户端流程
1.创建socket对象 2.连接服务器 3.发送数据 4.关闭对象
(2)服务器流程
1.创建socket套接字对象 2.绑定ip和端口 3.设置服务器处于监听状态 4.等待客户端连接 5.接收数据 6.关闭服务器套接字socket
由此可以看出,TCP服务器的流程比TC客户端流程多了两步,相比之下,略微复杂。
4.类方法解析
下述方法中的s表示一个tcp协议的socket对象。
1.s.bind() 用法同UDP。
2.s.listen(backlog)
s.listen(backlog)参数backlog:参数通常用于控制同时等待服务器接受的连接请求的数量。如果 backlog
的值设置为 5,意味着操作系统将最多允许 5 个未处理的连接请求在队列中等待。如果有更多
的连接请求到达,操作系统将拒绝它们。方法的作用:设置套接字监听队列的长度。
3.s.accept()
s.accept()在未收到客户端发来的数据前,该方法运行,使用程序一直处于阻塞状态。方法的作用:返回一个两个元素的元组。第1个元素为客户端socket对象,第2个元素
为客户端的地址,该数值同样是一个元组(包括ip和端口)。返回值格式:(<socket.socket fd=300, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 54518)>, ('127.0.0.1', 54518))
4.s.recv(num)
s.recv(num)参数num:数据类型为整数,表示一次从客户端接收的数量大小,数据单位为这字节。注意:此处的s表示客户端socket对象。
5.s.connect(serverAdress)
s.connect(serverAdress)参数serverAdress:为一个地址对象,含义中s.bind()中地址参数含义。注意此处的s.客户端对象。
6.s.send(sentContent)
send(data)参数data:客户端socket需要发送的二进制数据。传入的数据如果不是二进制数据,则需要
转化为二进制数据。比如如果需要为服务发送“Hello World”,则需要将字符串"Hello World"
转化为二进制数据,方法:"Hello World".encode("utf-8")
注意:客户端发送的字符串时encode()中编码参数与服务器收到字符串decode()中参数必须一至。
5.UDP和TCP使用的类方法区别
(1)UDP发送数据使用的方法是sendto(),而TCP发送数据使用的方法是send(),并且二者传参方式也不一样。
(2)UDP接收数据使用的方法是recvfrom(),而TCP接收数据使用的方法是recv()。前者调用该方法的对象是服务器对象,而后者调用该方法的对象是是客户端对象,并且二者的返回值不同。前者返回值是元组,后者返回值是二进制数据。
第一部分 基础知识
网络编程的目的
将多个设备通过网络进行连接在一起,可以将数据共享。
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.关闭套接字
02-遇到的问题说明

03-接收udp数据的程序
04-遇到的问题说明2
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
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()
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()
3.2运行结果:
4. 注意点
如果当前使用的这个udp端口正在使用中,如果此时有另外一个程序也是用的这个端口,那么就会出现“端口被占用”的问题
先运行一个程序,让其一直占用7788端口
然后再运行一个程序,让其也绑定这个端口,此时就会出现问题
5. 小总结
- 一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行此程序端口可能会发生变化
- 一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是给此进程的
3.2 绑定示例
08-绑定时的注意点1
老师小结
1.ip地址是本机电脑中的ip
(1)如果要是手动写上当前电脑的ip,可行,但是又个问题:如果重启电脑之后当前电脑的ip如果变了,那么这个程序中绑定的那个ip就需要修改,麻烦。
(2)一般来说,让python程序自动选择当前电脑的ip是一个很好的解决方案。当前电脑的ip是什么,那么就给这个程序绑定什么,一句话:自动识别然后绑定。
2.端口
(1)不能随便的绑定1-1023之间的端口。因为他们是知名端口号,不能随便使用,一般用来特殊的用途,例如22专门用来ssh远程连接使用的。
(2)如果当前的某个端口正在使用中,也不能绑定。在1024~65535端口号之间,如果这个端口正在被其他的程序使用,那么就不能再次绑定,除非刚刚用这个端口的程序结束。否则只能换端口号。
09-绑定的最核心原因
最核心的原因:如果要使用udp做一个服务的程序,那么这个程序应该先运行,并且需要一个明确的端口号,否则其他程序不能够把需要的请求数据发送给这个服务方的电脑 。
10-绑定时的注意点2

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等,就是为了能够将一个复杂的通信过程进行任务拆分为一个一个具体的任务,然后相互配合,从而保证数据准确无误的传递
12-案例:UDP聊天室
1.想法来源
去银行办理相关业务时,一般会先取号,然后等待叫号即可,如下圈所示·那么能否用python来写一个程序,模拟当前叫号显示牌呢?
老师说他的很多想法都来源于生活。
2.需求分析
1.需要用一个程序先运行
2.让这个程序一直等待接收 其他 程序发送过来的数据
3.接收数据之后显示出来
3.代码实现
13-案例:UDP聊天软件1
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的不同点
- 面向连接(确认有创建三方交握,连接已创建才作传输。)
- 有序数据传输
- 重发丢失的数据包
- 舍弃重复的数据包
- 无差错的数据传输
- 阻塞/流量控制
02-TCP的特点
03-TCP客户端
TCP客户端
1. 引入
为了区分,被服务的一方 和 提供服务的一方,网络中有客户端、服务器。
TCP客户端的代码流程与TCP服务器的代码流程不一样,因此需要单独学习。
2. 区分客户端、服务器
之前有一个段子:
一个顾客去饭馆吃饭,这个顾客要点菜,就问服务员咱们饭店用客户端么,然后这个服务员非常客气的说道:先生 我们饭店不用客户端,我们直接送到您的餐桌上
如果,不学习网络的知识 说不定也会发生那样的笑话 ,哈哈。
客户端:
需要服务的一方,例如我们用浏览器上个,浏览器帮助我们向远程的一台电脑发送请求接收数据,以及展示效果等,此时浏览器就是客户端。
服务器(端):
就是提供服务的一方,例如玩游戏时,需要登录的服务器。
3. 构建TCP客户端流程
试想玩在线游戏的时候的流程:
- 打开电脑
- 链接游戏服务器登录
- 玩游戏
- 退出游戏
TCP的客户端的实现过程很类似玩游戏的流程:
逻辑顺序如下:
- 创建一个TCP套接字(套接字不区分客户端、服务器)
- 链接服务器
- 向服务器发送数据、接收来自服务器的响应数据
- 断开链接
4. TCP客户端示例代码
4.1 只发送数据的示例
from socket import *# 1. 创建socket
tcp_client_socket = socket(AF_INET, SOCK_STREAM)# 2. 链接服务器
tcp_client_socket.connect(("192.168.1.104", 8080))# 提示用户输入数据
send_data = input("请输入要发送的数据:")# 3. 向服务器发送数据
tcp_client_socket.send(send_data.encode("utf-8"))# 4. 关闭套接字
tcp_client_socket.close()
当客户端发送完毕数据后,它立刻调用了close,即关闭了这个套接字,那么意味着双方之间的链接就断开了,因此服务器就不能向这个客户端发送数据
4.2 发送、接收数据的示例
import socket# 1. 创建TCP套接字
client_s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 2. 链接服务器
client_s.connect(("192.168.1.104", 8080))# 3. 获取要发送的数据
send_content = input("请输入要发送的数据内容:")# 4.1 发送数据
client_s.send(send_content.encode("utf-8"))# 4.2 接收数据
recv_content = client_s.recv(1024)
print(recv_content.decode("gbk"))# 5. 关闭套接字
client_s.close()
在客户端发送数据之后,因为它调用了recv,意味着要等待服务器发送数据,如果服务器没有发送它会在这里进行堵塞,直到服务器发送数据过来为止;在客户端调用close之前,服务器随时都可以进行发送数据。
5. 小总结
(一). TCP客户端的流程:
- 创建套接字
- 链接服务器
- 发送/接收数据
- 关闭套接字
(二). 虽然在学习TCP通信的过程中说:当收到数据后需要给对方发送确认消息,但那时操作系统做的事情,咱们编写的代码不需要确认,只管收发数据即可。
04-理解TCP客户端链接TCP服务器

05-TCP客户端-发送、接收数据

06-TCP服务器

07-TCP服务器先调用close会出问题
08-TCP服务器等客户端关闭后再关闭
结合老师所讲自己写的代码:
import socket
# 1.创建socket套接字对象
serverSocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2.绑定ip和端口
serverIPPort=("127.0.0.1", 8888)
serverSocket.bind(serverIPPort)
# 3.设置服务器处于监听状态
serverSocket.listen(128)
# 4.等待客户端连接
custumerSocket,custumerIPPort=serverSocket.accept()
# 5.接收客户端发送的数据及关闭客户端套接字socket
while True:recvContent=custumerSocket.recv(1024)if len(recvContent)!=0:print(recvContent)else:custumerSocket.close()break
# 6.关闭服务器套接字socket
serverSocket.close()
09-TCP客户单不能发送长度为0的数据
老师说,服务设置的while循环中,要求客服端发送的数据不能为空,否则,服务端会退出。如果连续发送的数据中存在空数据,一定要在编写客户端代码时,设置一个判断,不允许向服务器发送空数据。
.
10-TCP特点总结

11-案例:文件下载器-client

12-案例:文件下载器-server
13-案例:文件下载器-server-升级
14-案例:文件下载器-下载较thnn
第五部分 三握四挥(纯理论性知识,有空再学)
01-TCP3次握手【听得很懵逼有空再学】
三握四挥-02-TCP4次挥手
03-2MSL的问题,为什么先关
04-TCP4次挥手补充
TCP长连接、短连接
第六部分 wireshark抓包(属性了解性知识,有空再学)
01-wireshark介绍以及安装
02-wireshark网络抓包工具-使用1
03-wireshark网络抓包工具-使用2
第七部分 真正理解网络通信(网络通信模拟构件)
01-PacketTracer安装与使用
02-网络掩码的作用
03-通过交换机组一个局域网、arp获取mac地址
04-路由器的作用

05-由交换机、路由组网

06-浏览器输入网址后做了什么

07-网络通信过程:3个路由器怎么配置

08-通俗理解TCPIP协议
tcp-ip简介
作为新时代标杆的我们,已经离不开手机、离不开网络,对于互联网大家可能耳熟能详,但是计算机网络的出现比互联网要早很多。
1.什么是协议
有的说英语,有的说中文,有的说德语,说同一种语言的人可以交流,不同的语言之间就不行了为了解决不同种族人之间的语言沟通障碍,现规定国际通用语言是英语,这就是一个规定,这就是协议。
2.计算机网络沟通用什么
现在的生活中,不同的计算机只需要能够联网(有线无线都可以)那么就可以相互进行传递数据。
那么不同种类之间的计算机到底是怎么进行数据传递的呢?
就像说不同语言的人沟通一样,只要有一种大家都认可都进守的协议即可,那么这个计算机都遵守的网络通信协议叫做 TCP/IP协议。
3.TCP/IP协议(族)
早期的计算机网络,都是由各厂商自己规定一套协议,IBM、Apple和Microsott都有各自的网络协议,互不兼容。
为了把全世界的所有不同类型的计算机都连接起来,就必须规定一套全球通用的协议,为了实现互联网这个目标,互联网协议族(IntemetProtocolSuite)就是通用协议标准。
常用的网络协议如下图所示:
说明:
网际层也称为:网络层。
网络接口层也称为:链路层 。
另外一套标准