学习网络编程的的第二天,自己列几个自己认为比较关键的点,供复习使用,文章其他部分,也是绝大多数内容是转载的另外两篇,感觉还不错。
1、c/s架构 : client/server 架构
2、四/五个重要的层:
- 物理层:高低电压、二进制制——将数据转化为二进制进行发送
- 数据链路层:以太网(Ethernet)协议(what)、mac地址(where)、广播(how)——数据组成为
报头head+data
- 网络层:IP协议、IP地址——数据组成为
IP头+data
- 传输层:TCP/UDP协议 ——数据组成为
TCP/UDP头+data
- 应用层:HTTP协议等
3、简单描述如何实现两台计算机之间的通信:
① 局域网(内)的点对点通信:以太网协议
以太网协议(Ethernet)规定了电子信号如何组成数据包(packet),解决了子网内部的点对点通信。
但是,以太网协议不能解决多个局域网如何互通,这由 IP 协议解决。
② 多个局域网的通信:IP协议
IP 协议定义了一套自己的地址规则,称为 IP 地址。它实现了路由功能,允许某个局域网的 A 主机,向另一个局域网的 B 主机发送消息
路由器就是基于 IP 协议。局域网之间要靠路由器连接。
一句话:网络层的ip
对子网进行区分,以太网层(数据链路层)的mac
找到对应的特定主机,而端口
(应用程序与网卡关联的编号)最后识别出这台主机上的应用程序。
1. python网络编程初级总结
计算机基础 应用软件----操作系统---硬件
C/S架构就是 客户端---服务端
客户端:client应用软件----操作系统---硬件
服务端:server应用程序----操作系统---硬件
C-----S 客户端通过网卡传输数据到网络---回传给服务端网卡---继而服务端收到客户端数据(循环往复操作)
计算机进行通信需要一个世界标准式的 ”英语“ 这种标准协议就是互联网协议
(从下到上 类比发快递)
互联网的简化五层协议: 作用 协议 组成
物理层: 将数据转化为二进制进行发送
数据链路层: 整合处理数据 以太网协议 18个字节(源6、目标6----mac6地址),后6是数据
网络层: IP IP协议 6个字节数据 就是数据链路层的数据部分 IP头+data
传输层: 数据格式化传输 TCP/UDP协议 TCP/UDP头+data
应用层: http协议等 应用软件
-------------------------------------------------------------------------------------------------
# 数据链路层-----以太网协议是以mac地址为基础的广播模式传递消息(当然仅限是局域网内 广播mac地址才能被局域网中的用户接收到)
# 网络层-------IP协议
# 传输层------以TCP协议为例: TCP协议也称为是流式协议 所以数据传输需要建立双向水管(发送和接收数据)
TCP协议发送之后需要接收对方收到后的确认应答信号,没收到就重新发送--------------需要建立双向通道
1.客户端发送请求 syn=1 请求确认标志位 此请求的序列号x
2.服务端应答请求并发送一个请求 syn=1 请求标志位 此请求序列号为y
应答ack=1+x 应答标志位+请求序列号(序列号是为了确认该应答和请求是对应关系)
3.客户端发送应答信号ack=1+y 解释同上
---------------这就是TCP协议建立双向传输通道时的三次握手
1.客户端数据发送结束给服务端发送断开请求 F/N=1
2.服务端接收并应答ack=1
3.服务端数据发送结束给客户端发送断开请求 F/N=1
4.客户端接收并应答ack=1
----------------这就是TCP协议的四次挥手断开双向连接
PS: (2、3两步不能合并 因为有数据传输,客户端数据发送完毕不意味着服务端的数据也已经发送完毕)
UDP协议就是发送数据后继续发送,不管对方收到没,也不管对方是否存在,就是不断发送数据-----不需要建立双向通道
比较:TCP稳定可靠,但是传输效率低
UDP不稳定不可靠,但是传输效率高
# 包头都是固定长度的 这就是在定义一种标准
IP+MAC地址标识了全世界独一无二的那一台电脑
IP+端口标识了一台计算机上运行的某个软件 端口 0-65535 0-1024端口是分配给操作系统的,用户自定义端口是从1024开始
但是一般安装程序时会占用一些热门的端口,所以自定义端口从8888以后开始几乎不会发生端口冲突问题
#PS: 服务端的程序需要固定IP+端口 就像卖菜一样,一天一个地方,老顾客根本无法准确找到你(既然你是服务端,以服务大众为己任)
客户端不需要固定IP+端口 因为买菜的人不分哪里的,随时去买
大致可以猜出 C/S之间的通讯流程就是:S需要先绑定IP+端口 并监听端口记录访客 C只需要利用端口去访问S就可以了
了解ARP协议:就是只要知道对方的IP地址就能够找到对方 因为ARP协议会自动解析IP地址为相应的mac地址 说到底还是IP+MAC地址
------------------------------------------------------------------------------------
正式学习socket套接字编程:
Socket抽象层位于应用层和传输层之间
我们要写通信软件就必须要实现应用层和底部四层之间的连接关系,但是光一个传输层就够你研究很久了,什么时候才能写出来软件呢?
所以有大佬就已经封装好了传输层及其以下的四层连接,并向应用层提供了调用接口
所以我们的学习就是学习如何使用socket抽象层的接口去实现 C/S客户端的通信交互
-----socket抽象层 就是位于应用层和传输层之间的 主要用来处理传输层以及以下层的处理,我们只需要处理应用层和socket层接口对接
两大类别
1.基于文件类型的套接字编程
AF_UNIX 设计实现同一台主机上多个应用程序之间的通讯
2.基于网络类型的套接字编程
AF_INET 设计实现两台不同主机间的应用程序的通信交互
客户端的connect(客户端请求连接) ------- 服务端的accept(服务端等待并应答连接)
相当于是接待员接待客户后转交给某个服务员conn
命令:
1.windows操作系统
1.1 dir 查看某个文件夹下的文件以及文件夹名
1.2ipconfig 查看本地网卡的IP信息
1.3tasklist 查看运行的进程
2.Linux操作系统
2.1 ls
2.2 ifconfig
2.3 ps aux
----------------------------------------------------
客户端的发包send 其实就是通过操作系统将客户端程序的内存中的包数据拿到自己的内存中,再去调用网卡驱动传输数据 recv收包包括
send和recv的对比终极底层分析:
1.不管是recv还是send都不是直接接收和发送数据给对方,而是操作自己的操作系统内存--->不是一个send对应一个recv(可以累计接收累计发送)
2.recv两大阶段:
1.远程服务器发包传到本地操作系统内存中,耗时很长 等待数据
2.再从本地操作系统内存中取包数据 拷贝数据
2. 利用提供的C/S程序 自己去测试两个命令
#---------------------利用提供的C/S程序 自己去测试两个命令
命令:
1.windows操作系统
1.1 dir 查看某个文件夹下的文件以及文件夹名
1.2ipconfig 查看本地网卡的IP信息
1.3tasklist 查看运行的进程
2.Linux操作系统
2.1 ls
2.2 ifconfig
2.3 ps aux
# 客户端程序
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
# 收发消息
while True:
# 发送命令
cmd = input('>>>').strip()
if not cmd:continue
client.send(cmd.encode('utf-8'))
# 拿到结果并打印
data = client.recv(1024)
print(data.decode('gbk')) # 这里的编码是根据自己的操作系统的
client.close()
# 服务端程序
import socket
import subprocess
# 1.创建socket对象
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 这行代码的作用是回收重用IP+端口
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 2.绑定端口
server.bind(('127.0.0.1', 8080))
# 3.监听
server.listen(5)
# 4.等待连接
while True:
conn, client_Addr = server.accept()
# 5收发消息
# 5.1.接收数据
while True:
try:
cmd = conn.recv(1024) # 接收数据的最大字节数
# 拿到命令后去执行
obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
stderr = obj.stderr.read()
stdout = obj.stdout.read()
# 执行命令后去返回结果
conn.send(stderr + stdout) # 发送消息都是二进制格式
except ConnectionResetError as e:
break
conn.close()
server.close()
以上代码执行后就会发现出现粘包现象
以上代码执行后就会发现出现粘包现象
---------------------------------------------------------------------------------------------------------
粘包现象其实就是底层优化算法nigo造成的:如果数据量小并且时间间隔短的话,send会合并为大数据块进行发送
比如:第一次send 一个字节 间隔很短接着send 两个字节 就会合并发送send 三个字节
----------------------------------------------------只有TCP数据传输才会有粘包现象
UDP协议:没有粘包现象,因为没有连接没有优化算法的影响 并且一个send对应一个recv
3. 网络编程
服务端
1、创建socket
2、端口绑定
3、开启监听
4、持续等待连接
5、获取请求
6、回复请求
7、关闭连接
客户端
1、创建对象
2、获取连接
3、发送请求
4、接收数据
5、断开连接
代码
#!C:/Users/Administrator/AppData/Local/Programs/Python/Python37/python.exe
#coding=gbk#一定要注意设置字符编码,否则很可能报错
import socket
import sys
# 1、创建socket对象
serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2、绑定
host = socket.gethostname()
port = 9999
serversocket.bind((host,port))
# 3、监听,设置最大连接数,超出后排队
serversocket.listen(5)
#4、等待接入
while True:
clientsocket,addr = serversocket.accept()
print("连接地址:%s"% str(addr))#返回的第一个值为服务器信息,第二个值为客户端信息
msg="欢迎访问菜鸟教程"
#5、主动发送消息
clientsocket.send(msg.encode("utf-8"))
#6、接收请求
#7、关闭连接
clientsocket.close()
#!C:/Users/Administrator/AppData/Local/Programs/Python/Python37/python.exe
import socket
import sys
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = socket.gethostname()
port = 9999
s.connect((host,port))
msg= s.recv(1024)
s.close()
print(msg.decode("utf-8"))
要点:socket套接字其实就是一个特殊的文本,里面存储着用于通讯的地址和端口,还有一些协议,fid,这些我们通过打印socket可以的知道, 我们要注意的是,在服务器端的首次创建出的socke套接字只用于绑定端口和设置监听,真正用来进程通讯的是通过accept()返回的第一个参数(clientsocket),即用于通讯的套接字,里面含有服务端地址,服务端用于服务的端口,客户端地址,客户端用于通讯的端口,地址是用来网络寻址找到对应电子设备(电脑等),端口则是用于进程间的通讯。所以我们可以知道,如果有3个客户端连接服务器,那么服务器端将有4个套接字,1个是服务器端用于绑定和监听的套接字,3个分别与客户端通信的套接字,每个客户端都有一个用于与服务端通信的套接字。
更多参考:python之网络编程——是大神啊!值得深入研究!
参考:
- python网络编程初级总结(1)——这个宝宝的总结都很精炼啊,可以翻一翻
- python学习总结-网络编程