1、软件开发架构 web
咱们了解的涉及到两个程序之间的通信大体能够分为两种:算法
应用类:qq、微信、网盘、优酷这一类是属于须要安装的桌面应用设计模式
web类:好比百度、知乎、博客园等使用浏览器访问就能够直接使用的应用浏览器
这些应用的本质其实都是两个程序之间的通信。而这两个分类又对应了两个软件开发的架构~缓存
1,C/S架构 服务器
C/S即:Client与Server ,中文意思:客户端与服务器端架构,这种架构也是从用户层面(也能够是物理层面)来划分的。微信
这里的客户端通常泛指客户端应用程序EXE,程序须要先安装后,才能运行在用户的电脑上,对用户的电脑操做系统环境依赖较大网络
2,B/S架构 多线程
B/S即:Browser与Server,中文意思:浏览器端与服务器端架构,这种架构是从用户层面来划分的。架构
Browser浏览器,其实也是一种Client客户端,只是这个客户端不须要你们去安装什么应用程序,只需在浏览器上经过HTTP请求服务器端相关的资源(网页资源),客户端Browser浏览器就能进行增删改查。
2、网络基础
1,ip地址精确到具体的一台电脑,而端口精确到具体的程序。
2,osi七层模型
人们按照分工不一样把互联网协议从逻辑上划分了层级:
3,socket
socket一般也称做‘’套接字”,用于描述ip地址和端口,是一个通讯链的句柄,应用程序一般经过‘套接字’向网络发出请求或者应答网络请求。
理解:socket是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口。在设计模式上socket就是一个门面模式,它把复杂的TCP/IP协议族隐藏在socket接口后面,对用户来讲一组简单的接口就是所有,让socket去组织数据,以符合指定的协议。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操做。socket就是该模式的一个实现,socket便是一种特殊的文件,一些socket函数就是对其进行的操做(读/写IO、打开、关闭)
socket和file的区别:
4,tcp协议和udp协议
TCP(Transmission Control Protocol)可靠的、面向链接的协议,传输效率低全双工通讯(发送缓存&接收缓存)、面向字节流。使用tcp的应用:web浏览器,电子邮件,文件传输程序。
UDP(User Datagram Protocol)不可靠的无链接的服务,传输效率高,一对一,一对多,多对一,多对多,面向报文,无拥塞控制.使用udp的应用:域名系统(DNS)、视频流、ip语音
tcp协议:
udp协议:
更多功能:
参数一:地址簇 socket.AF_INET IPv4(默认) socket.AF_INET6 IPv6 socket.AF_UNIX 只可以用于单一的Unix系统进程间通讯 参数二:类型 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 可靠的连续数据包服务 参数三:协议 0 (默认)与特定的地址家族相关的协议,若是是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议
sk.bind(address) s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。 sk.listen(backlog) 开始监听传入链接。backlog指定在拒绝链接以前,能够挂起的最大链接数量。 backlog等于5,表示内核已经接到了链接请求,但服务器尚未调用accept进行处理的链接个数最大为5 这个值不能无限大,由于要在内核中维护链接队列 sk.setblocking(bool) 是否阻塞(默认True),若是设置False,那么accept和recv时一旦无数据,则报错。 sk.accept() 接受链接并返回(conn,address),其中conn是新的套接字对象,能够用来接收和发送数据。address是链接客户端的地址。 接收TCP 客户的链接(阻塞式)等待链接的到来 sk.connect(address) 链接到address处的套接字。通常,address的格式为元组(hostname,port),若是链接出错,返回socket.error错误。 sk.connect_ex(address) 同上,只不过会有返回值,链接成功时返回 0 ,链接失败时候返回编码,例如:10061 sk.close() 关闭套接字 sk.recv(bufsize[,flag]) 接受套接字的数据。数据以字符串形式返回,bufsize指定最多能够接收的数量。flag提供有关消息的其余信息,一般能够忽略。 sk.recvfrom(bufsize[.flag]) 与recv()相似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 sk.send(string[,flag]) 将string中的数据发送到链接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容所有发送。 sk.sendall(string[,flag]) 将string中的数据发送到链接的套接字,但在返回以前会尝试发送全部数据。成功返回None,失败则抛出异常。 内部经过递归调用send,将全部内容发送出去。 sk.sendto(string[,flag],address) 将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。 sk.settimeout(timeout) 设置套接字操做的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。通常,超时期应该在刚建立套接字时设置,由于它们可能用于链接的操做(如 client 链接最多等待5s ) sk.getpeername() 返回链接套接字的远程地址。返回值一般是元组(ipaddr,port)。 sk.getsockname() 返回套接字本身的地址。一般是一个元组(ipaddr,port) sk.fileno() 套接字的文件描述符
3、黏包
同时执行多条命令以后,获得的结果极可能只有一部分,在执行其余命令的时候,又接收到以前执行的一部分结果,这种现象就是黏包。
注意:只有TCP有黏包,UDP没有黏包现象。
黏包成因:
TCP(transport control protocol,传输控制协议)是面向链接的,面向流的,提供高可靠性服务。
收发两端(客户端和服务器端)都要有一一成对的socket,所以,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将屡次间隔较小且数据量小的数据,
合并成一个大的数据块,而后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通讯是无消息保护边界的。
对于空消息:tcp是基于数据流的,因而收发的消息不能为空,这就须要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即使是你输入的是空内容(直接回车,
也能够被发送,udp协议会帮你封装上消息头发送过去。可靠黏包的tcp协议:tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端老是在收到ack时才会清除缓冲区内容。
数据是可靠的,可是会粘包。
会发生黏包的两种状况:
接收方不及时接收缓冲区的包,形成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候仍是从缓冲区拿上次遗留的数据,产生粘包)
总结:
1.从表面上看,黏包问题主要是由于发送方和接收方的缓存机制、tcp协议面向流通讯的特色。
2.实际上,主要仍是由于接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所形成的。
问题的根源在于,接收端不知道发送端将要传送的字节流的长度,因此解决粘包的方法就是围绕,如何让发送端在发送数据前,把本身将要发送的字节流总大小让接收端知晓,而后接收端来一个死循环接收完全部数据。
存在的问题:
程序的运行速度远快于网络传输速度,因此在发送一段字节前,先用send去发送该字节流长度,这种方式会放大网络延迟带来的性能损耗
咱们能够借助一个模块,这个模块能够把要发送的数据长度转换成固定长度的字节。这样客户端每次接收消息以前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小,那么最终接受的数据只要达到这个值就中止,就能恰好很少很多的接收完整的数据了。
socketserver模块
SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每一个客户端请求链接到服务器时,Socket服务端都会在服务器是建立一个“线程”或者“进程” 专门负责处理当前客户端的全部请求。
ThreadingTCPServer
ThreadingTCPServer实现的Soket服务器内部会为每一个client建立一个 “线程”,该线程用来和客户端进行交互。
一、ThreadingTCPServer基础
使用ThreadingTCPServer:
二、ThreadingTCPServer源码剖析
ThreadingTCPServer的类图关系以下:
内部调用流程为:
ForkingTCPServer
ForkingTCPServer和ThreadingTCPServer的使用和执行流程基本一致,只不过在内部分别为请求者创建 “线程” 和 “进程”。