前言:
什么是网络?
网络是由节点和连线构成, 表示诸多对象及其相互联系.
在数学上, 网络是一种图, 一般认为专指加权图.
网络除了数学定义外, 还有具体的物理含义, 即网络是从某种相同类 型的实际问题中抽象出来的模型
在计算机领域中, 网络是信息传输, 接收, 共享的虚拟平台, 通过它把各个点, 面, 体的信息联系到一起, 从而实现这些资源的共享.
网络是人类发展史 https://baike.sogou.com/lemma/ShowInnerLink.htm?lemmaId=8054344&ss_c=ssc.citiao.link 来最重要的发明, 提高了科技和人类社会的发展.
在 1999 年之前, 人们一般认为网络的结构都是随机的. 但随着 Barabasi 和 Watts 在 1999 年分别发现了网络的无标度和小世界 特性并分别在世界著名的科学 和自然 杂志上 发表了他们的发现之后, 人们才认识到网络的复杂性.
网络会借助文字阅读, 图片查看, 影音播放, 下载传输, 游戏, 聊天等软件工具从文字, 图片, 声音, 视频等方面给人们带来极其丰富的生活和美好的享受.
网络目的:
网络传输的目的是什么?
没错就是: 数据传输
由于网络的复杂性以及各种应用硬件等等不匹配原因
和编码是一个道理你有你的我有我的会导致冲突等问题
所以出现了 :ISO(国际标准化组织)
ISO 是干嘛的呢?
他是一个非盈利性国际组织 这个组织制定了一个用于计算机或通讯系统间的互联网标准体系
叫 OSI 模型 不仅包括一系列抽象的术语或概念, 也包括具体的协议
OSI 公有七层 :
应用层: 提供用户服务, 具体的内容由特定的程序规定
表示层: 提供数据的加密和压缩优化
会话层: 确定建立应用链接, 选择传输服务
传输层: 提供数据传输服务, 进行流量控制
网络层: 路由选着, 网络互联
链路层: 提供链路交换, 具体消息的发送
物理层: 物理硬件, 接口, 网卡的规定
或
四层模型:
应用层 : 应用层 表示层 会话层
传输层 : 传输层
网络层 : 网络层
物理链路层: 链路层和物理层
或
五层模型 (tcp/ip 模型):
应用层 : 应用层 表示层 会话层
传输层 : 传输层
网络层 : 网络层
链路层 : 链路层
物理层 : 物理层
OSI 模型优点:
将功能分开 降低网络中的耦合度,
使用开发流程更加清晰, 每部分各司其职
高内聚低耦合:
高内聚: 每个模块功能尽量单一, 不会多个功能掺杂
低耦合: 尽量降低每个模块之间的关联性
网络协议:
在网络通讯中协议必须遵守的规定,
如建立什么连接, 消息结构如何解析等
应用层: TFTP(文件传输),HTTP(超文本传输协议),DNS(域名解析),SMTP(邮件传输)
传输层: TCP,UDP
网络层: IP
物理层: IEEE
iPython3:socket 模块
网络相关概念:
网络主机: 在网络上确定一台主机
本地使用: 127.0.0.1 或 "localhost"
网络地址:"0.0.0.0" 或 "172.168.40.53"
ifconfig: 查看本机 IP (ens33: 本地 IP lo: 本地回还)
ipconfig:windoes 中
socket.gethostname() : 获取本机主机名
socket.gethostbyname('tedu') : 利用主机名获取 ip
socket.gethostbyname('localhost'): 获取本地 ip
常用 IP 地址:
IPv4: 点分十进制 例如: 192.168.1.3 取值 0~255(32 位)
IPv6: 128 位
网络连接测试
ping 172.18.32.47
特殊 ip
127.0.0.1 本地 IP 测试
0.0.0.0 自动使用本地可用网卡 IP
192.168.1.0 代表网段
192.168.1.1 通常为网关地址
192.168.1.255 广播地址
访问主机 IP 地址:
- socket.gethostbyaddr('127.0.0.1')
- ('localhost', [], ['127.0.0.1'])
主机 别名 ip 地址
IP 十六进制转换:
- socket.inet_aton('192.168.1.2')
- b'\xc0\xa8\x01\x02'
- socket.inet_ntoa(b'\xc0\xa8\x01\02')
- '192.168.1.2'
域名:
是指网络服务器地址在网络上的名称
端口号:
端口号是地址的一部分, 在一个系统中每个网络 (区分应用 ip)
应用监听不同的端口, 以获取对应的端口传递信息
取值范围: 1---------65535
1---------255 一些通用端口 (众所周知的程序占用)
256------1023 系统端口
1024-----65535 自用端口
获取应用程序的端口:
- socket.getservbyname('ssh')
- 22
- socket.getservbyname('mysql')
- 3306
传输层服务:
面向连接的传输服务 (tcp 协议):
传输特征:
可靠的数据传输:
可靠性: 无失序, 无差错, 无重复, 无丢失
在数据传输前和传输后需要建立连接和断开链接
面向传输服务建立连接的过程:'三次握手'
客户端向服务器发送链接请求
服务器接受到请求进行确认, 返回确认报文
客户端收到服务器回复最终确认链接
面向传输服务断开链接的过程:'四次挥手'
主动方发送报文, 告知被动方要断开链接
被动方回复报文, 表示已经接受到请求, 准备断开
被动方再次发送报文, 表示准备处理就绪, 可以断开
主动方发送确认报文, 断开链接
应用情况:
适用于传输较大的内容或文件, 网络良好,
需要保证传输可靠性的情况
e.g. 信息聊天, 文件上传下载, 邮件, 网页获取
面向无连接的传输服务 (udp 协议):
不保证传输的可靠性
没有建立连接和断开的过程
数据的收发比较自由
适用情况:
网络情况较差, 对可靠性要求不高, 收发消息的两端
e.g.: 网络视频, 群聊, 广播等
socket 套接字编程:
目的:
通过编程语言提供的套接字编程接口
可以更简单的完成基于 tcp/udp 的编程
套接字:
是完成上述目标的一种编程手段
套接字类别:
1. 流式套接字 (SOCK_STREAM):
传输层基于套接字的协议通信
面向连接可靠的传输 tcp 的传输 流式套接字
2. 数据报套接字 (SOCK_DGRAM):
面向无连接不可靠的传输 udp 的传输 数据报套接字
3. 低层套接字 (SOCK_RAM):
访问底层协议套接字
TCP 服务端:
import socket
1. 创建套接字 (函数):
- socket.socket(sock_family = AF_INET,
- sock_type = SOCK_STREAM,
- proto = 0)
功能:
创建套接字
参数:
sock_family 地址族类型 AF_INET:IPV4 网络通讯
sock_tpye: 套接字类型 SICK_STREAM : 流式 SOCK_DGRAM: 数据报
proto: 通常为 0 选定子协议类型
返回值: 返回一个套接字对象
2. 绑定地址 (函数):
sockfd.bind(addr)
功能:
绑定地址
参数:
addr---> 元组 (ip, port) ("0.0.0.0", 8888)
3. 设置监听套接字:
sockfd.listen(n)
功能:
将套接字设置为监听套接字, 创建监听队列
参数:
监听队列大小
一个监听套接字可以连接多个客户端
4. 等待接受客户端链接:
connfd,addr = sockfd.accept() 阻塞状态
功能:
阻塞等待并处理客户端链接
返回值:
connfd: 新的套接字, 用于和客户端通讯
addr: 链接客户端的地址 (ip, port)
阻塞函数:
当程序运行到阻塞函数位置, 如果某种条件
没有达成则暂停程序运行, 直到条件达成结束阻塞
-
5. 消息的收发:
data = connfd.recv(buffersize)
功能:
接受消息
参数:
一次接受消息的大小 字节
返回值: 返回接受的内容
n = connfd.send(data)
功能:
发送消息
参数:
要发送的内容 (bytes 格式)
返回值: 返回实际发送的字节数
6. 关闭套接字
sockfd.close()
客户端:
1. 创建套接字 (和服务端套接字类型相同)
2. 发起链接
connect(addr)
功能:
向服务端发起链接
参数:
服务器地址 (元组)
3. 消息收发
4. 关闭套接字
示例
服务端:
- from socket import *
- # 创建套接字对象
- sockd = socket()
- # 绑定 IP 地址
- sockd.bind(("127.0.0.1", 6666))
- # 设置监听套接字
- sockd.listen(5)
- # 等待客户端链接
- cond, addr = sockd.accept()
- # 接受客户端消息 (单次 1024 字节)
- data = cond.recv(1024)
- print(data.decode())
- # 发送消息
- cond.send(b"Hello, I'm the server")
- # 关闭套接字
- cond.close()
- sockd.close()
这里本机测试可以利用两个进行 telnet 命令链接服务端测试
服务器:
- from socket import *
- # 创建套接字
- sockfd = socket(AF_INET, SOCK_STREAM)
- # 绑定地址
- sockfd.bind(("0.0.0.0", 8888))
- # 设置监听
- sockfd.listen(5)
- # 等待客户端链接
- print("waiting for connect....")
- conn, addr = sockfd.accept()
- print("Connect from", addr)
- print("Connect from", conn)
- # 消息收发
- while True:
- data = conn.recv(1024)
- if data.decode() == "":
- n = conn.send(b"Bey")
- break
- print("Receive", data.decode())
- n = conn.send(b"Receive your message")
- print("send %d" % n)
- # 关闭套接字
- conn.close()
- sockfd.close()
客户端:
- # tcp_client.py
- from socket import *
- sockfd = socket()
- sockfd.connect(("172.18.32.31", 8888))
- while True:
- msg = input("Msg>>")
- if msg == "":
- break
- sockfd.send(msg.encode())
- data = sockfd.recv(1024)
- # if msg == "Bye":
- # break
- print(data.decode())
- sockfd.close()
简单的消息传输:
来源: http://www.bubuko.com/infodetail-2717549.html