今天来记录一下网络编程:对于网络的理解以及各种通信协议,这个也是后端开发的基础知识
(1)网络通信的概念
什么是网络:网络就是一种辅助双方或者多方能够连接在一起的工具,就是为了联通多方之后进行通信用的,把数据从一方传递给另外一方,为了让在不同的电脑上运行的软件之间能够互相传递数据,就需要借助网络的功能。
简练:使用网络能够把多方链接在一起,然后可以进行数据传递,所谓的网络编程就是让在不同的电脑上的软件能够进行数据传递,即进程之间的通信
(2)通信协议:tcp/ip
白话协议:为了解决不同种族人之间的语言沟通障碍,现规定国际通用语言是英语,这就是一个规定,这就是协议。就像说不同语言的人沟通一样,只要有一种大家都认可都遵守的协议即可,那么这个计算机都遵守的网络通信协议叫做 TCP/IP协议
—TCP/IP协议不是两种协议,他是一种协议族
(3)TCP/IP协议中的端口:端口针对于有网络需求的进程来说的
什么是端口:端口就好比一个房子的门,是出入这间房子的必经之路。***如果一个进程需要收发网络数据,那么就需要有这样的端口***在linux系统中,端口可以有65536(2的16次方)个之多,既然有这么多,操作系统为了统一管理,所以进行了编号,这就是端口号(形象的比喻:端口就是一个门,进程是房子)想要进房子首先需要通过门—端口
端口号:端口是通过端口号来标记的,端口号只有整数,范围是从0到65535,端口号不是随意使用的,而是按照一定的规定进行分配的,有知名端口以及动态端口
动态端口:动态端口的范围是从1024到65535,之所以称为动态端口,是因为它一般不固定分配某种服务,而是动态分配。
动态分配是指当一个系统进程或应用程序进程需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配一个供它使用。当这个进程关闭时,同时也就释放了所占用的端口号。
查看端口: netstat -an 查看端口状态
或者: lsof -i:端口号 推荐使用:lsof -i:端口号
或者:netstat -ap | grep 端口号
总结:一台拥有IP地址的主机可以提供许多服务,比如HTTP(万维网服务)、FTP(文件传输)、SMTP(电子邮件)等,这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系。实际上是通过“IP地址+端口号”来区分不同的服务的。需要注意的是,端口并不是一一对应的。比如你的电脑作为客户机访问一台WWW服务器时,WWW服务器使用“80”端口与你的电脑通信,但你的电脑则可能使用“3457”这样的端口。(ip地址和端口)
(4)ip地址
ip地址:用来在网络中标记一台电脑的一串数字,比如192.168.1.1;在本地局域网上是惟一的。每一个IP地址包括两部分:网络地址和主机地址。ip地址分为A、B、C、D、E类
私有IP:在这么多网络IP中,国际规定有一部分IP地址是用于我们的局域网使用,也就是属于私网IP,不在公网中使用,他们的范围是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255
IP地址127.0.0.1~127.255.255.255用于回路测试,如:127.0.0.1可以代表本机IP地址,用 http://127.0.0.1 就可以测试本机
中配置的Web服务器。
(5)子网掩码
子网掩码的功能就是确定IP地址中哪些是网络号、哪些是主机号
(6)通信基元–socket
本地的进程间通信:
队列
同步(互斥锁、条件变量)
这种通信都是在一台机器上不同进程之间的通信方式,网络中进程之间如何通信?
----需要解决的问题是如何唯一标识一个进程,否则通信无从谈起,在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。TCP/IP协议已经帮我们解决类这个问题,网络层的ip地址可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的引用程序(进程)。这样利用ip地址、协议、端口就可以标识网络的进程类,网络中的进程通信就可以利用这个标志与其他进程进行交互
什么是scoket: socket(套接字)是进程间通信的一种方式,它与其他进程间的一个主要不同是,他能实现不同主机间的进程间通信,网络上各种各样的服务大多都是基于Socket来完成通信的,我们每天浏览网页、QQ、wechat等等
(7)创建socket
在python中使用socket模块中的socket就可以创建socket
创建一个tcp socket(tcp套接字)
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket Created'
创建一个udp socket(udp套接字)
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print 'Socket Created'
(8)UDP介绍
UDP和TCP一样都是网络通信协议–用于解决网络中数据的传输问题
UDP—用户数据报协议,是一个无连接(对于无连接的理解,客户端和服务器端在通信之前不需要进行连接,然而TCP需要)的简单的面向数据报的运输层协议
UDP性能:UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。UDP是一种面向无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
UDP特点:
UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。 UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内。UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
UDP适用情况:
UDP是面向消息的协议,通信时不需要建立连接,数据的传输自然是不可靠的,UDP一般用于多点通信和实时的数据业务,比如
语音广播
视频
QQ
TFTP(简单文件传送)
SNMP(简单网络管理协议)
RIP(路由信息协议,如报告股票市场,航空信息)
DNS(域名解释)
UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。
UDP只管传送,不管对方有没有接收到信息-------(这个就是数据传输不可靠的因素)。
(9)udp网络程序-发送数据
UDP通信的过程图:
创建一个udp客户端程序的流程是简单,具体步骤如下:
客户端:
#coding=utf-8
from socket import *
#1. 创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
#2. 准备接收方的地址
sendAddr = ('192.168.1.103', 8080)
#3. 从键盘获取数据
sendData = raw_input("请输入要发送的数据:")
#4. 发送数据到指定的电脑上
udpSocket.sendto(sendData, sendAddr)
#5. 关闭套接字
udpSocket.close()
----创建udp网络程序-接收数据
一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行次程序端口可能会发生变化一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程的
udp总结:
(10)TFTP协议介绍
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文件传输的协议
(11)tcp相关介绍
udp通信模型:udp通信模型中,在通信开始之前,不需要建立相关的连接,只需要发送数据就可以,类似于生活中的“写信”
UDP通信模型图:
tcp通信模型
TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,“打电话”"
UDP/TCP都是网络通信协议-------
UDP:无连接,用户数据报协议
TCP:有连接
TCP网络通信协议图:
tcp服务器:比作生活中的电话机
如果想让别人能更够打通咱们的电话获取相应服务的话,需要做一下几件情:
```bash
#coding=utf-8
from socket import *
# 创建socket
tcpSerSocket = socket(AF_INET, SOCK_STREAM)
# 绑定本地信息
address = ('', 7788)
tcpSerSocket.bind(address)
# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收
tcpSerSocket.listen(5)
# 如果有新的客户端来链接服务器,那么就产生一个新的套接字专⻔为这个客户端服务器
# newSocket用来为这个客户端服务
# tcpSerSocket就可以省下来专⻔等待其他新客户端的链接
newSocket, clientAddr = tcpSerSocket.accept()
# 接收对方发送过来的数据,最大接收1024个字节
recvData = newSocket.recv(1024)
print '接收到的数据为:',recvData
# 发送一些数据到客户端
newSocket.send("thank you !")
# 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需
newSocket.close()
# 关闭监听套接字,只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的连接
tcpSerSocket.close()
tcp服务器的一套流程
-----tcp客户端构建流程
tcp的客户端要比服务器端简单很多,如果说服务器端是需要自己买手机、查手机卡、设置铃声、等待别人打电话流程的话,那么客户端就只需要找一个电话亭,拿起电话拨打即可,流程要少很多
客户端:使用服务器的ip+端口进行打电话
具体的代码如下:
#coding=utf-8
from socket import *
# 创建socket
tcpClientSocket =socket(AF_INET,SOCK_STREAM)
# 链接服务器
serAddr =('192.168.1.102', 7788)
tcpClientSocket.connect(serAddr)
# 提示用户输入数据
sendData=raw_input("请输入要发送的数据:")
tcpClientSocket.send(sendData)
# 接收对方发送过来的数据,最大接收1024个字节
recvData=tcpClientSocket.recv(1024)
print'接收到的数据为:',recvData
# 关闭套接字
tcpClientSocket.close()
客户端的写法比较简单
(12)网络通信过程
网络通信组网,多台电脑组网、集线器组网、交换机组网、路由器组网,交换机和路由器组网。
集线器组网:
集线器能够完成多个电脑的连接,每个数据包的发送都是以广播的形式进行的,容易堵塞网络
网络交换机组网:
网络交换机是一个扩大网络的器材,能为子网络中提供更多的连接端口,以便链接更多的计算机
路由器组网:
路由器称为网关设备,是用于连接多个逻辑上分开的网络,逻辑网络是代表一个单独的网络或者一个子网。当数据从一个子网输到凉意个子网时,可通过路由功能来完成
(13)tcp的三次握手
当两个socket建立连接时需要进行三次握手的操作(也就是客户端和服务器端建立连接时)
客户端 服务器端
第一次握手:客户端发送请求,服务器端接受请求
第二次握手:服务器端接受到请求,反馈给客户端
第三次握手:客户端接受到服务器端的反馈,发送确认信息,建立连接完成握手操作
(14)tcp四次挥手
两个socket之间要断开连接,客户端和服务器端需要断开连接。
第一次挥手:客户端给服务器端发送fn
第二次挥手:服务器收到fn,并反馈
第三次挥手:服务器再次发送信息给客户端
第四次挥手:客户端接受信息,给服务器端发送确认关闭连接,完成断开连接的操作
(15)tcp的长连接和短连接
TCP在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时可以释放这个连接
连接的建立通过三次握手,释放则需要四次挥手,所以说每个连接的建立都是需要资源消耗和时间消耗的。
短连接:
TCP短连接
模拟一种TCP短连接的情况:
client向server发起连接请求
server接到请求,双方建立连接
client向server发送消息
server回应client
一次读写完成,此时双方任何一个都可以发起close操作
TCP长连接:
再模拟一种⻓连接的情况:
client向server发起连接
server接到请求,双方建立连接
client向server发送消息
server回应client
一次读写完成,连接不关闭
后续读写操作…
长时间操作之后client发起关闭请求
(16)TCP长/短连接的优点和缺点
TCP⻓/短连接的优点和缺点
⻓连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。
对于频繁请求资源的客户来说,较适用⻓连接。
client与server之间的连接如果一直不关闭的话,会存在一个问题,
随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,如关闭一些⻓时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损;
如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大⻓连接数,这样可以完全避免某个蛋疼的客户端连累后端服务。短连接对于服务器来说管理较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但如果客户请求频繁,将在TCP的建立和关闭操作上浪费时间和带宽。
(17)TCP长/短连接的应用场景
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多的情况,
场景:
一般数据库的连接需要用长连接,如果用短连接频繁的通信会造成socket的错误
像WEB网站的http服务一般都用短连接,因为长连接对于服务端来说会耗费一定的资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接,可想而知,并发量太大,所以web端使用短连接比较好
(18)socket中listen的队列长度
listen的队列长度,写在服务器端中,listen中的black表示已经建立连接和半连接达到设定值,那么新客户端就不会connect成功,而是等待服务器
在ubuntu中查看域名解析器的ip地址方法:nslookup 域名
nslookup www.baidu.com
(19)服务器
—1. 单进程服务器: (同一时刻只能为同一个客户端进行服务)完成一个简单的TCP服务器,同一时刻只能为一个客户进行服务,不能同时为多个客户服务。当服务器为一个客户端服务时,而另外的客户端发起了connect,只要服务器listen的队列有空闲的位置,就会为这个新客户端进行连接,并且客户端可以发送数据,但当服务器为这个新客户端服务时,可能一次性把所有数据接收完毕。
—2.多进程服务器(不推荐使用的)
通过为每个客户端创建一个进程的方式,能够同时为多个客户端进行服务。
当客户端不是特别多的时候,这种方式还行,如果有几百上千个,就不可取了,因为每次创建进程等过程需要好较大的资源。来一个客户端服务器就会单独开一个进程来对其进行服务
—3. 多线程服务器
通过为每个客户端创建一个线程的方式,能够同时为多个客户端进行服务。
—4. 单进程服务器-非堵塞模式
—5. select版-TCP服务器
在多路复用的模型中,比较常用的有select模型和epoll模型。这两个都是系统接口,由操作系统提供。
优点:select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。
缺点: select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024。当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间
—6. epoll版-TCP服务器
epoll的优点:
没有最大并发连接的限制,能打开的FD(指的是文件描述符,通俗的理解就是套接字对应的数字编号)的上限远大于1024
(20)协程
协程,又称为微线程,纤程–coroutine
通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。
核心:单线程中,由开发者来进行调度的(切换不同程序的执行)
协程和线程差异: 那么这个过程看起来比线程差不多。其实不然, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。
简单版本协程的实现:
import time
def A():while True:print("----A---")yieldtime.sleep(0.5)
def B(c):while True:print("----B---")c.next()time.sleep(0.5)
if __name__=='__main__':a = A()B(a)
(21)协程-greenlet版
为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单
(22)gevent
greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块 gevent 其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO
(23)思考协程
tornado中封装了协程异步,使用协程的方式来实现异步的操作
----异步web操作,服务器作为客户端的时候,需要进行异步的操作,保证作为服务器的功能(tornado中是单线程,单进程的,实现高并发的是epoll机制,以及协程操作)