标签:说话 控制 占用 可靠传输 理解 ftp服务 客户端程序 元组 通话
网络编程就是 1.udp 2.tcp
UDP可以理解为"写信"
什么是ip地址
ip地址: 用来在网络总唯一标识一台机器(个人PC,服务器,路由器,交换机....)
查看本机ip地址
ip地址的分类
什么是端口
1.ip地址就类似于一栋楼的地址,而端口号就类似于门牌号
ip地址找到目标主机,端口号找到目标进程
2. linux系统总,端口可以有 2**16(65535)个之多
端口通过端口号来标记,端口号只有整数,范围 [0,65535]
端口是怎样分配的
端口号不是随意使用的,而是按照一定的规定进行分配
端口的分类标准有好几种,这里介绍(1) 知名端口 (2) 动态端口
知名端口
1. 知名端口就是众所周知的端口,范围 [0,1023]
2. (1)如80端口分配给给HTTP服务 (2) 21端口分配给FTP服务
可以理解为一些常用的电话(大家都是知道的),比如火警119,救护车120之类的,不会有人专门使用电话号码和这些号码重名
3. 一般情况瞎,如果一个程序要使用知名端口需要有root权限
动态端口
大于2024的端口都是可以随意用的,但是知名端口是不能用的
1. 动态端口范围是从[1024,65535]
2. 之所以
之为动态端口,是因为它一般不固定分配某种服务,而是动态分配
3. 动态分配是指一个系统程序或引用程序需要网络通信时,它想主机申请一个端口,主机从可用的端口号中分配一个供它使用. 当这个程序关闭时,同时也就释放了所占用的端口.
怎样查看端口
最原始的网络编程 => socket
Python使用socket和使用file其实差不多
什么是socket
socket是一种实现在不同主机之间进程通信的一种方式
1. socket(简称套接字)是进程间通信的一种方式,它与其他进程间通信的一个主要不同是: 它能是实现不同主机间的进程间通信
(1) 我们网络上各种各样的服务大多都是基于socket来完成通信的,例如浏览网页,QQ聊天
创建socket
在Python中,使用socket模块的函数socket就可以完成创建一个socket
import socket
socket.socket(AddressFamily, Type)
1. 函数socket.socket创建一个 socket,该函数有两个参数:
(1) Address Family: 可以选择AF_INET(用户Internet进程间通信)或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET(ipv4),AF_INET(ipv6)
(2) Type: 套接字类型,可以是SOCK_STREAM(流式套接字,主要用于TCP协议)或者SOCK_DGRAM(数据报套接字,主要用于UDP协议)
2. 套接字使用流程和文件的使用流程很类似
(a) 创建套接字
(b) 使用套接字收发数据
(c) 关闭套接字
# 创建一个 tcp socket
import socket
s = socket.socket(socket.AF_INET,sock.SOCK_STREAM)
# 使用套接字功能
s.close()
# 创建一个 udp socket
import socket
s = socket.socket(socket.AF_INET,sock.SOCK_DGRAM)
# 使用套接字功能
s.close()
socket_udp收发数据实验
# code02_socket循环发送数据.py
import socket
def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
data = input("请输入要发送的数据(exit|quit): ").strip()
if data in ("exit", "quit"):
break
udp_socket.sendto(data.encode("gbk"), ("192.168.50.210", 8080))
udp_socket.close()
if __name__ == "__main__":
main()
# code03_绑定端口接收数据.py
import socket
def main():
# 1. 创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 绑定一个本地端口 => socket.bind()
# 如果一个网络程序不绑定,则系统会随机分配
local_addr = (‘‘, 7788) # ip端口号和地址,ip一般不用写,标识本机的任何一个ip
udp_socket.bind(local_addr)
while True:
# 3. 接收数据并打印输出
# 使用socket发送的输一个元组,接收的也是一个元组
# (b"",("ip地址",端口号))
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
print(recv_data[0].decode("gbk"))
# 4. 关闭套接字
udp_socket.close()
if __name__ == "__main__":
main()
str => bytes : encode 编码过程
bytes => str: decode 解码过程
# 首先str.encode()就是把 字符串转换为字节 (在Python中有 b-str)
>>> "这是一个文本字符串".encode()
b‘\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\x80\xe4\xb8\xaa\xe6\x96\x87\xe6\x9c\xac\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2‘
# str.encode()还可以接收参数
>>> "这是一个文本字符串".encode("utf-8")
b‘\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\x80\xe4\xb8\xaa\xe6\x96\x87\xe6\x9c\xac\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2‘
# 对应 str -> bytes -> str
>>> "这是一个文本字符串".encode("utf-8").decode("utf-8")
‘这是一个文本字符串‘
>>> b‘\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\x80\xe4\xb8\xaa\xe6\x96\x87\xe6\x9c\xac\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2‘.decode("utf-8")
‘这是一个文本字符串‘
其中decode()与encode()方法可以接受参数,其声明分别为
bytes.decode(encoding="utf-8", errors="strict")
str.encode(encoding="utf-8", errors="strict")
其中的encoding是指在解码编码过程中使用的编码(此处指“编码方案”是名词),errors是指错误的处理方案
会变的网络端口
1. 每次重新运行一次网络程序,下图中红圈的数字都会变化,变化的原因在于,由于程序没有绑定固定的端口号 (socket.bind()) 所以系统会随机分配一个空闲的端口
2. 客户端一般是不需要使用 socket.bind() 绑定一个地址的,因为客户端进程存活时间相对较短,且客户端套接字为主动套接字,服务器在接收数据时动态地获取客户端地址已能满足需求 => 所以客户端程序不需要绑定固定端口号,有系统随机分配即可
3. 一个udp网络程序,可以不不绑定端口号,此时操作系统会随机进行分配一个端口,如果重新运行此程序端口会发生变化; 也可以进行端口的绑定,这样就是固定使用这个端口号
全双工,半双工,单工
举几个简单例子来理解概念
1. 单工: 收音机 (只能是 A => B)
2. 半双工: 对讲机 (可以实现A <=> B,但是在A => B或者B => A的时候,另外一方是不能发送的)
3. 全双工: 电话 (A<=>B 同一时刻既可以收又可以发) [socket是全双工特性的]
udp聊天器
# code04_udp聊天室_服务器.py
import socket
def main():
# 创建socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 地址绑定
udp_socket.bind(("", 3456))
# 接收数据并打印
print("-" * 10 + "聊天室" + "-" * 10)
while True:
recv_info = udp_socket.recvfrom(1024)
address = f"{recv_info[1][0]}:{recv_info[1][1]}"
print(address)
print(recv_info[0].decode("gbk"))
# 关闭socket
udp_socket.close()
if __name__ == "__main__":
main()
# code05_udp聊天室_客户端.py
import socket
def main():
# 创建socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 向服务器发送数据
print("-" * 10 + "输入框" + "-" * 10)
while True:
data = input()
client_socket.sendto(data.encode("gbk"), ("localhost", 3456))
if data.strip() in ("exit", "quit"): break
# 关闭socket
client_socket.close()
if __name__ == "__main__":
main()
TCP可以理解为"打电话"
tcp介绍
1. TCP协议,传输控制协议(Transmission Control Protocol,缩写为 TCP).
2. TCP是一种 面向连接的, 可靠的,基于 字节流 的 传输层 通信协议.
3. TCP通信需要经过 (1)创建连接 (2) 数据传送 (3) 终止连接 三个步骤.
(1) TCP通信模型中,在通信开始之前,一定要先监理相关的链接,才能发送数据,类似于生活中"打电话".
tcp特点
1. 面向连接
(1) 通信双方必须建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输.
(2) 双方的数据传输都可以通过这一个连接进行.
(3) 完成数据交换后,双方必须断开此连接,以释放系统资源.
(4) 这种连接时一对一的, 因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议.
2. 可靠传输
(1) TCP采用发送应答机制
(a) TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功.
(2) 超时重传
(a) 发送段发出一个报文段之后就启动定时器,如果在定时时间内没有受到应答就重新发送这个报文段.
(b) TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包按序接收. 然后接收端实体对已成功受到的包发挥一个相应的确认(ACK); 如果发送段实体在合理的往返时延(RTT)内未收到确认,那么对一个的数据包就被假设为已丢失,将会被进行重传.
(c)前面的两点,可以形象理解为打电话,然后A说话,B一定时间没有应答, 那么A就会重新在把刚才的话说多一次
(d) 每次看电脑在下载一个东西,也有上传的数据,其实这个上传的数据就是TCP的应答数据.
(3) 错误校验
(a) TCP用一个校验和函数来检验数据是否有错误; 在发送和接收时都要计算校验和.
(4) 流量控制和阻塞管理
(a) 流量控制用来避免主机发送得过快而使接收方来不及完全收下.
(b) 流量控制也是非常关键的,发送端50G的文件不能一股脑的发过来,要合理流量和控制,不然接收方不能成功接收.
TCP和UDP的不同点
TCP => 打电话
UDP => 写信
1. 面向连接(确认有创建三次握手,连接已创建才进行传输)
2. 有序数据传输
3. 重发丢失的数据包
4. 舍弃重复的数据包
5. 无差错的数据传输
6. 阻塞/流量控制
UDP通信模型
TCP通信模型
tcp客户端
1. tcp是严格区分客户端和服务器的
2. 所谓的服务器端,就是提供服务的一方,而客户端,就是需要被服务的一方.
tcp客户端构建流程
1. tcp的客户端比服务器端简单很多
2. 如果说服务器端是需要自己买手机,插电话卡,设置铃声,等待别人打电话这些样的流程,那么客户端就只需要找一个电话亭,拿起电话拨打即可,流程要少很多.
# code06_tcp_client.py
import socket
def main():
# 创建tcp的套接字
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 链接服务器
# 使用 socket.connect() 来链接服务器
server_ip = input("请输入服务器ip: ").strip()
server_port = int(input("请输入服务器port: ").strip())
server_addr = (server_ip,server_port)
tcp_socket.connect(server_addr)
# 发送数据/接收数据
# 这里已经建立了通道,所有使用 socket.send() UDP 使用 socket.sendto()
while True:
send_data = input("请输入要发送的数据(exit): ").strip()
if send_data == "exit":break
tcp_socket.send(send_data.encode("gbk"))
# 关闭套接字
tcp_socket.close()
if __name__ == "__main__":
main()
tcp是严格区分客户端和服务器的
tcp服务器
用电话机的过程来理解tcp服务器端
1. 买个手机 <=> socket创建一个套接字
2. 插上手机卡 <=> bind绑定ip和port
3. 设置手机为正常接听状态(即能够响铃) <=> listen使套接字变为被动链接
4. 静静的等待别人拨打 <=> accept等待客户端的连接
5. 进行通话 <=> recv/send 接收发送数据
标签:说话 控制 占用 可靠传输 理解 ftp服务 客户端程序 元组 通话
原文地址:https://www.cnblogs.com/Rowry/p/12709511.html