网络编程TCP
1 网络基础相关的知识
架构:
1. C / S架构 : client客户端 和 server服务器端
优势 : 能充分发挥PC机的性能
2. B / S架构 : browser浏览器 和 server服务器 隶属于C/S架构
B / S架构 统一了应用的接口.
通信:
1. 同一台电脑上两个py程序通信 : 打开一个文件
2. 两个电脑如何通信 : 连一个网线
3. 多个电脑通信 :
ex : 电脑1(源)要找电脑2(目标)
电脑1首先发送一个请求帧,期中包含(我的ip是192.168.1.1,我的mac地址是xxxxxxxx,我要找ip地址为192.168.1.2的主机),将此请求发送给交换机.
交换机要广播这条消息给其他所有的主机
目标主机接收到消息后,对比发现自己就是被找的主机,回复给交换机信息(我的ip地址是192.168.1.2,我的mac地址是yyyyyyyyy,请回复给ip地址为192.168.1.1,mac地址为xxxxxxx的主机)
交换机单播形式返回给源主机
1 mac地址 : 是一个物理地址,全球唯一, 类似于身份证
head中包含的源和目标地址由来:ethernet规定接入internet的设备都必须具备网卡,发送端和接收端的地址便是指网卡的地址,即mac地址。
mac地址:每块网卡出厂时都被烧制上一个世界唯一的mac地址,长度为48位2进制,通常由12位16进制数表示(前六位是厂商编号,后六位是流水线号)
2 ip地址: 是一个四位点分十进制,它标识了计算机在网络中的位置.
- 规定网络地址的协议叫ip协议,它定义的地址称之为ip地址,广泛采用的v4版本即ipv4,它规定网络地址由32位2进制表示
- 范围0.0.0.0-255.255.255.255
- 一个ip地址通常写成四段十进制数,例:172.16.10.1
3 交换机的通信方式:
广播
主机之间“一对所有”的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要),由于其不用路径选择,所以其网络成本可以很低廉。有线电视网就是典型的广播型网络,我们的电视机实际上是接受到所有频道的信号,但只将一个频道的信号还原成画面。在数据网络中也允许广播的存在,但其被限制在二层交换机的局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机。
4 arp协议 : 通过目标ip地址获取目标mac地址的一个协议.
地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。
5 端口 : 操作系统为本机上每一个运行的程序都随机分配一个端口,其他电脑上的程序可以通过端口获取到这个程序
ip地址 + 端口 能唯一找到某台电脑上的某一个服务程序
我们知道,一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等,这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP 地址与网络服务的关系是一对多的关系。实际上是通过“IP地址+端口号”来区分不同的服务的。
6 路由器 : 连接不同网段 , 路由
路由器(Router),是连接因特网中各局域网、广域网的设备,它会根据信道的情况自动选择和设定路由,以最佳路径,按前后顺序发送信号。 路由器是互联网络的枢纽,"交通警察"。目前路由器已经广泛应用于各行各业,各种不同档次的产品已成为实现各种骨干网内部连接、骨干网间互联和骨干网与互联网互联互通业务的主力军。路由和交换机之间的主要区别就是交换机发生在OSI参考模型第二层(数据链路层),而路由发生在第三层,即网络层。这一区别决定了路由和交换机在移动信息的过程中需使用不同的控制信息,所以说两者实现各自功能的方式是不同的。
![](https://images2018.cnblogs.com/blog/1432837/201808/1432837-20180810153513488-2044625462.png)
7 网关 : 类似于一个局域网的出口和入口
8 网段 : 一个局域网内的ip地址范围
9 子网掩码 : 子网掩码 & ip地址 得到网段
所谓”子网掩码”,就是表示子网络特征的一个参数。它在形式上等同于IP地址,也是一个32位二进制数字,它的网络部分全部为1,主机部分全部为0。比如,IP地址172.16.10.1,如果已知网络部分是前24位,主机部分是后8位,那么子网络掩码就是11111111.11111111.11111111.00000000,写成十进制就是255.255.255.0。
知道”子网掩码”,我们就能判断,任意两个IP地址是否处在同一个子网络。方法是将两个IP地址与子网掩码分别进行AND运算(两个数位都为1,运算结果为1,否则为0),然后比较结果是否相同,如果是的话,就表明它们在同一个子网络中,否则就不是。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 比如,已知IP地址172.16.10.1和172.16.10.2的子网掩码都是255.255.255.0,请问它们是否在同一个子网络?两者与子网掩码分别进行AND运算, 2 3 172.16.10.1:10101100.00010000.00001010.000000001 4 255255.255.255.0:11111111.11111111.11111111.00000000 5 AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0 6 7 8 9 172.16.10.2:10101100.00010000.00001010.000000010 10 255255.255.255.0:11111111.11111111.11111111.00000000 11 AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0 12 结果都是172.16.10.0,因此它们在同一个子网络。
10 osi 五层模型:
应用层 : http,https,ftp
传输层 : tcp / udp 四层交换机 四层路由器
网络层 : ip协议 路由器 三层交换机
数据链路层 : arp协议 以太网交换机 网卡 网桥
物理层 : 传输电信号 集线器 网线 光纤
每层运行常见物理设备
每层运行常见的协议
socket概念
1socket层
2理解socket
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
其实站在你的角度上看,socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。
也有人将socket说成ip+port,因为ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序。
所以我们只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信。
3.套接字(socket)的发展史
套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。
基于文件类型的套接字家族
套接字家族的名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
基于网络类型的套接字家族
套接字家族的名字:AF_INET
(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)
family :
一种 : AF_UNIX基于文件类型的套接字(早期socket是源自于unix系统而研发的一个功能,主要是为了同一台电脑上,多个程序直接通信) unix系统的中心思想是 : 一切皆文件
一种 : AF_INET基于网络类型的套接字
type:
一种是基于TCP协议 SOCK_STREAM
一种是基于UDP协议 SOCK_DGRAM
tcp 协议 : 可靠的,面向连接的,面向字节流形式的传输方式
udp协议 : 不可靠的,不面向连接的,面向数据报的传输方式,但是它快
套接字(socket)初使用
server.py文件import socket import time sk=socket.socket() # 不传参数,默认使用基于网络类型的套接字, 协议 : TCP sk.bind(("192.168.12.39",10000)) # 端口的范围是0-65535 但是 0-1023 这些你别用 sk.listen() # 同时能接受的连接 print(123456) conn,addr = sk.accept() # 等待接受客户端的连接 阻塞等待 print(789) print('conn:',conn) time.sleep(15) conn.close() sk.close()
client.py文件 import socket import time sk = socket.socket() sk.connect(("192.168.12.39",10000)) time.sleep(15) sk.close()
通信
server.py文件 import socket sk=socket.socket() # 我买一个新手机 sk.bind(("192.168.12.39",10000)) # 我买一个手机卡 sk.listen() # 开机 print(123456) conn,addr = sk.accept() # 等待朋友给我打电话 ret=conn.recv(100) # 接受数据,接受100个字节 print(ret.decode("utf-8"),addr) conn.close() sk.close()
client.py文件 import socket sk = socket.socket() sk.connect(("192.168.12.39",10000)) sk.send("我是你哥".encode("utf-8")) sk.close()
回环地址 : 127.0.0.1 每个计算机都有的这么一个本机地址,只能被本机识别,不会被其它机器识别
与单人通信
服务器 import socket sk=socket.socket() sk.bind(("127.0.0.1",65534)) sk.listen() conn,addr=sk.accept() while 1: ret=conn.recv(1024).decode("utf-8") print(ret) if ret=="q": break content=input(">>>>") conn.send(content.encode("utf-8")) if content=="q": break conn.close() sk.close() 客户端 import socket sk=socket.socket() sk.connect(("127.0.0.1",65534)) while 1: content=input(">>>>") sk.send(content.encode("utf-8")) if content == "q": break ret=sk.recv(1024).decode("utf-8") print(ret) if ret == "q": break sk.close()
与单人轮流通信
服务器 import socket sk=socket.socket() sk.bind(("127.0.0.1",65534)) sk.listen() while 1: conn,addr=sk.accept() while 1: ret=conn.recv(1024).decode("utf-8") print(ret) if ret=="q": break content=input(">>>>") conn.send(content.encode("utf-8")) if content=="q": break conn.close() sk.close() 客户端 import socket sk=socket.socket() sk.connect(("127.0.0.1",65534)) while 1: content=input(">>>>") sk.send(content.encode("utf-8")) if content == "q": break ret=sk.recv(1024).decode("utf-8") print(ret) if ret == "q": break sk.close()
tcp三次握手: 一定是client先发起请求
a 客户端发起请求连接服务器
b 服务器返回 : 接收到请求,并要求连接客户端
c 客户端回复 : 可以连接
四次挥手: 谁先发起断开连接的请求都可以
a 客户端发起断开连接的请求:
意思是: 我想和你断开连接,我没有数据要继续发送了,但是如果你有数据需要发送,我可以继续接收
b 服务器回复 : 我接收到你的请求了
c 服务器发送 : 我已经准备好断开连接了
d 客户端回复 : 收到你的信息,断开连接
与多人署名轮流聊天
服务器 import socket sk=socket.socket() sk.bind(("127.0.0.1",6554)) sk.listen() while 1: conn,addr=sk.accept() while 1: ret=conn.recv(1024).decode("utf-8") print(ret) if ret== "q": break content=input(">>>>") conn.send(content.encode("utf-8")) if content == "q": break conn.close() sk.close() 客户端 import socket sk=socket.socket() sk.connect(("127.0.0.1",6554)) name=input("输入名字:") while 1: content=input(">>>>") use_name=name+":"+content sk.send(use_name.encode("utf-8")) if content == "q": break ret=sk.recv(1024).decode("utf-8") print(ret) if ret == "q": break sk.close()