网络基础
什么是网络?
物理连接各台计算机的设备
为什么有网络?
为了方便数据传输,让沟通没有边界。
socket:
socket把传输层及其以下都封装好了
socket抽象层,从osi七层抽象出来,抽象了网络层与传输层,与任何语言无关。
arp协议:
负责把ip解析成mac地址
储备知识一 通信分为两大类:
1.目标主机在局域网内
2.目标主机不在局域网内
储备知识二:ip与子网掩码
ip作用
1.ARP协议会依据IP地址解析成mac地址
2.ip + 子网掩码与运算会得到网络地址,判断是否在一个局域网内
通信的前提:先拿到目标的ip与端口
arp协议的工作步骤:
1.依据自己的ip与子网掩码计算出自己的网络地址
2.依据对方的IP与子网掩码计算出对方的网络地址、
3.判断1和2的网络地址是否一致
3.1如果一样,证明源与目地在同一局域网内,只需走交换机即可。
arp协议包
源mac FF-FF-FF-FF-FF-FF 源ip 目的ip 数据部分
发送真实的数据包
源mac 目的mac地址 源ip 网关的IP 数据部分
3.2如果不一样,证明源与目地在同一局域网内,需要走交换机再发给路由器,路由器再走运营商网络
发arp协议广播包 ->拿到网关的mac
源mac FF-FF-FF-FF-FF-FF 源ip 网关的IP 数据部分
发送真实的数据包
源mac 网关的mac地址 源ip 网关的IP 数据部分
交换机只有两种情况广播:
1.目标mac为 FF-FF-FF-FF-FF-FF
2.目标mac地址不在mac地址表上
子网划分:借主机位给网络位用,把原来一个网段变成多个网段
效果:
1.减少了ip的浪费
2.缩小了广播域
网络编程:
常用协议默认端口:
TCP概述
TCP把连接作为最基本的对象,每一条TCP链接都有两个端点,这种端点我们叫做套接字(socket)
它的定义为端口号拼接到IP地址即构成了套接字。
tcp连接的建立(三次握手)
1.最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。
2.TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
3.TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。
4.TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。
5.TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。
TCP四次挥手:
1.数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。
2.客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
3.服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
4.客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
5.服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
6.客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗ *∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
7.服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
socket:
基于文件类型的套接字家族
套接字家族的名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
基于网络类型的套接字家族
套接字家族的名字:AF_INET
(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)
什么是Scoket?
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
import socket
# socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0
socket.socket(socket_family, socket_type, protocal=0)
# 获取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能大幅减短我们的代码
tcpSock = socket(AF_INET, SOCK_STREAM)