Python Day29 网络协议
~为何学习socket一定要先学习互联网协议:
1.首先:本节课程的目标就是教会你如何基于socket编程,来开发一款自己的C/S架构软件
2.其次:C/S架构的软件(软件属于应用层)是基于网络进行通信的
3.然后:网络的核心即一堆协议,协议即标准,你想开发一款基于网络通信的软件,就必须遵循这些标准。
~~~~
===== 互联网协议 osi七层协议 ===== 应用层 + 传输层 + 网络层 + 网络接口层 4层 应用层 + 传输层 + 网络层 + (数据链路层+物理层) 5层 (应用层 + 表示层 + 会话层)+ 传输层 + 网络层 + (数据链路层+物理层) 7层 1) 物理层 ----- 硬件的标准---- >>> 发送电信号------对应数字 0,1 2) 数据链路层 ----以太网协议 ethernet (根据物理层的信号 分组) mac地址===>>> 局域网的地址 一组电信号 构成一个数据包(帧) ---每一帧: head(接受者是谁 + 发送者是谁 + 数据类型) + data mac 地址:ethernet规定 internet设备 都必须有网卡---mac地址(发送 接收端的地址) 广播: ethernet 通过 广播的方式通信 广播包 只能在一个局域网内通信 3) 网络层---- ip 协议 (ipv4 ipv6) ip地址===>>> 确认子网地址 ipv4 与 子网掩码 二进制---按位与运算(前三段一样) 172.16.10.1(点分十进制) + 255.255.255.0 --->> 172.16.10.0 (子网的地址 范围) 不在一个地址 把包传给网关 是一个 出口 (相当海关于) -- 跨子网通信 ---路由协议 ARP 协议(ip找到mac)----- 把 ip地址 转换为一个 网关地址 ----方便子网内 mac广播通信 ip+mac ==== >>> 唯一的一台机器 4) 传输层 ----- 传输层功能:建立端口到端口的通信 (包 传输头) () 标识这台主机上的应用程序,就是端口,端口即应用程序与网卡关联的编号 ip + 端口 --->> 唯一的软件 用户应用层的内存中的数据 --->> 操作系统内存中 --->> 网卡 ----发送 双向连接---那端的数据输完--可以先断掉 tcp 协议 ---- 可靠协议---建立连接3次握手 -----数据传输玩---客户端响应 断开连接4次挥手 -- udp 协议 ---- 不可靠协议 5) 应用层 ------应用层产生数据---数据包 (包一个 应用层头) 应用层功能:规定应用程序的数据格式 发数据---封包 ------
~~~~
socket.SOCK_STREAM 流式socket , for TCP (默认)
socket.SOCK_DGRAM 数据报式socket , for UDP
socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET 可靠的连续数据包服务
****区别:
SOCK_STREAM 是有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料(如文件)传送。
SOCK_DGRAM 是无保障的面向消息的socket , 主要用于在网络上发广播信息。
SOCK_STREAM是基于TCP的,数据传输比较有保障。SOCK_DGRAM是基于UDP的,专门用于局域网,基于广播
SOCK_STREAM 是数据流,一般是tcp/ip协议的编程,SOCK_DGRAM分是数据包,是udp协议网络编程
解释一下:
关于UDP
1、UDP协议适用端口分辨运行在同一台设备上的多个应用程序,UDP有不提供数据报分组、组装和不能对数据包进行排序的缺点。
也就是说,当报文发送之后,是无法得知其是否安全完整到达的。
2、在网络质量令人不十分满意的环境下,UDP协议数据包丢失会比较严重。
3、但是由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
关于TCP
1、TCP提供端到端、全双工通信;采用字节流方式,如果字节流太长,将其分段;提供紧急数据传送功能。
2、TCP特性:
(1)面向连接的传输;
(2)端到端的通信;
(3)高可靠性,确保传输数据的正确性,不出现丢失或乱序;
(4)全双工方式传输;
(5)采用字节流方式,即以字节为单位传输字节序列;
(6)紧急数据传送功能。
如果需要传输的数据是准确的,建议采用TCP,也就是SOCK_STREAM
如果你传输的是视频音频等数据,丢几个包也无所谓的,可以采用UDP,也就是SOCK_DGRAM
一、socket层
二、socket是什么
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
三、套接字工作流程
一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。
先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束
~~~socket()模块函数用法
import socket socket.socket(socket_family,socket_type,protocal=0) socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 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)
服务端套接字函数
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来
客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间
面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件
三、基于TCP的套接字
tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端
tcp服务端:
ss = socket() #创建服务器套接字 ss.bind() #把地址绑定到套接字 ss.listen() #监听链接 inf_loop: #服务器无限循环 cs = ss.accept() #接受客户端链接 comm_loop: #通讯循环 cs.recv()/cs.send() #对话(接收与发送) cs.close() #关闭客户端套接字 ss.close() #关闭服务器套接字(可选)
tcp客户端:
1 cs = socket() # 创建客户套接字 2 cs.connect() # 尝试连接服务器 3 comm_loop: # 通讯循环 4 cs.send()/cs.recv() # 对话(发送/接收) 5 cs.close() # 关闭客户套接字