码迷,mamicode.com
首页 > Web开发 > 详细

django基础一:web、wsgi、mvc、mtv

时间:2017-10-01 23:49:28      阅读:354      评论:0      收藏:0      [点我收藏+]

标签:title   编码   ati   tle   udp协议   udp   串口助手   arch   开发   

一、web框架

  web框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以快速开发特定的系统。他山之石,可以攻玉。python的所有web框架,都是对socket进行封装的。

  web应用本质上是一个socket服务端,用户的浏览器是一个socket客户端。socket处在应用层与传输层之间,是操作系统中I/O系统的延伸部分(接口),负责系统进程和应用之间的通信。【python网络编程基础】

  上面这个解释看起来有点费劲。重新解释一遍:

  socket是在应用层和传输层之间的一个抽象层,扮演“信使”角色。它把tcp/ip层复杂的操作抽象为几个简单的接口以供应用层调用,从而实现在网络中通信。

  django是python web开发的主流框架,另外还有flask和tensorflow。django框架必须掌握,要学精通。

  web应用的流程:

//浏览器发送一个HTTP请求;
//服务器收到请求,根据请求信息,进行函数处理,生成一个HTML文档;
//服务器把HTML文档作为HTTP响应的Body发送给浏览器;
//浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示;

  回顾一下socket的udp连接和tcp连接,注:查看当前进程和杀死进程的window命令:

    netstat -ano|findstr 45678

    taskkill -PID 45678的进程 -F

  udp客户端和服务端

技术分享
import socket
# upd链接
# SOCK_DGRAM:数据报套接字,主要用于UDP协议
udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 关闭防火墙
# 同一网段(局域网)下,主机的ip地址和端口号.
sendAddr = (192.168.10.247, 8080)

# 绑定端口:写的是自己的ip和固定的端口,一般是写在sever端.
udpSocket.bind((‘‘, 9900))

# sendData = bytes(input(‘请输入要发送的数据:‘), ‘gbk‘)
# gbk, utf8, str
sendData = input(请输入要发送的数据:).encode(gbk)

# python3是unicode编码,也就是以unicode格式写成的字节.
# encode,重写编码:就是把unicode环境下的数据,重新编码成指定格式的字节,比如gbk, utf8等.然后接收方以同样的解码格式解码.
# 用网络串口助手作为udp的服务端.网络串口助手是字节和十六进制的字节,没有unicode编码,有gbk编码和utf8编码.所以要解码成gbk
# 反过来,接收数据的时候,也要知道对方发送的数据要怎么解码.

# 使用udp发送数据,每一次发送都需要写上接收方的ip地址和端口号
udpSocket.sendto(sendData, sendAddr)
# udpSocket.sendto(b‘hahahaha‘, (‘192.168.10.247‘, 8080))

udpSocket.close()
udp客户端
技术分享
import socket

udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 接收方一般需要绑定端口
# ‘‘表示自己电脑的任何一个ip,即无线和有限同时连接或者电脑有不同的网卡(桥接),会有多个ip.
# 绑定自己的端口
bindAddr = (‘‘, 7788)
udpSocket.bind(bindAddr)

recvData = udpSocket.recvfrom(1024)
# print(recvData)
print(recvData[0].decode(gbk))

udpSocket.close()
# recvData的格式:(data, (‘ip‘, 端口)).它是一个元组,前面是数据,后面是一个包含ip和端口的元组.
udp服务端

  tcp客户端和服务端

技术分享
import socket

tcpClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serverAddr = (192.168.10.247, 8899)

# tcp的三次握手,写进了这一句话
tcpClient.connect(serverAddr)

sendData = input(‘‘)

# 直接用send就行了,udp是用sendto
tcpClient.send(sendData.encode(gbk))

recvData = tcpClient.recv(1024)

print(接收到的数据为:%s % recvData.decode(gbk))

tcpClient.close()

# 为什么用send而不是sendto?因为tcp连接是事先链接好了,后面就直接发就行了。前面的connect已经连接好了,后面直接用send发送即可。
# 而udp必须用sendto,是发一次数据,连接一次。必须要指定对方的ip和port。
# 相同的道理,在tcpServer端,要写recv,而不是recvfrom来接收数据
tcp客户端
技术分享
import socket
tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServer.bind((‘‘, 8899))
tcpServer.listen(5)

# tcp的三次握手,写进了这一句话当中
tcpClient, tcpClientInfo = tcpServer.accept()
# tcpServer.accept(),不需要写ip,可以接收多个客户端的。但事先要绑定端口和接入的客户端的数量
# client 表示接入的新的客户端
# clientInfo 表示接入的新的客户端的ip和端口port

recvData = tcpClient.recv(1024)
print(%s: %s % (str(tcpClientInfo), recvData.decode(gbk)))

# tcp的四次握手,写进了这一句话
tcpClient.close()
tcpServer.close()

# tcpServer.accept():等待客户端的接入,自带堵塞功能:即必须接入客户端,然后往下执行
# tcpClient.recv(1024): 也是堵塞,不输入数据就一直等待,不往下执行.
# tcpServer创建了两个套接字,一个是Server,另一个是tcpClient.Server负责监听接入的Client,再为其创建专门的tcpClient进行通信.
tcp服务端

  两个小实例:tcpServer开启循环模式,以及udp的多线程聊天室

技术分享
import socket

Server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

Server.bind((‘‘, 9000))
Server.listen(10)

while True:
    # 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务
    serverThisClient, ClientInfo = Server.accept()
    print(Waiting connect......)

    # 如果客户发送的数据是空的,那么断开连接
    while True:
        recvData = serverThisClient.recv(1024)
        if len(recvData) > 1:

            print(recv: %s % recvData.decode(gbk))

            sendData = input(send: )
            serverThisClient.send(sendData.encode(gbk))
        else:
            print(再见!)
            break
    serverThisClient.close()
开启循环模式
技术分享
from threading import Thread
import socket
# 收数据,然后打印
def recvData():
    while True:
        recvInfo = udpSocket.recvfrom(1024)
        print(%s:%s % (str(recvInfo[1]), recvInfo[0].decode(gbk)))

# 检测键盘,发数据
def sendData():
    while True:
        sendInfo = input(‘‘)
        udpSocket.sendto(sendInfo.encode(gbk), (destIp, destPort))

udpSocket = None
destIp = ‘‘
destPort = 0
# 多线程
def main():

    global udpSocket
    global destIp
    global destPort

    destIp = input(对方的ip: )
    destPort = int(input(对方的端口:))

    udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udpSocket.bind((‘‘, 45678))

    tr = Thread(target=recvData)
    ts = Thread(target=sendData)

    tr.start()
    ts.start()

    tr.join()
    ts.join()
if __name__ == __main__:
    main()
多线程聊天室

  根据以上socket,可以写一个简单的web应用

技术分享
import socket

def handle_request(client):
    buf = client.recv(1024)     # 请求头
    print(buf.decode(utf8))
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))       # 响应头
    client.send("<h1 style=‘color:red‘>Hello, yuan</h1>".encode("utf8"))    # body数据
    # 把上面的html写到当前文件夹下的html里,把上行代码换成下面代码,就是一个web基本的流程.
    # with open(‘hello.html‘, ‘rb‘) as f:
    #     data = f.read()
    # client.send(data)

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((localhost,8001))
    sock.listen(5)

    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == __main__:
    main()

# 在浏览器中输入localhost:8001,显示红色字体的hello,yuan.
# 在后台Terminal中,会输出buf的内容:
‘‘‘
GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:8001
Connection: Keep-Alive
Cookie: csrftoken=pW12OxqURLh8VgHwwR1TzlR65ubxDzZgBv9SJtXZZeKuqd38TWGyntT84gX29rtr
‘‘‘
最简单的web小程序

二、WSGI

  接收HTTP请求,解析HTTP请求,发送HTTP响应(如上面显示的)涉及到TCP连接、HTTP原始请求和响应格式。它涉及到底层较为复杂的构造:

  根据网络通信的OSI模型,应用层封装一次数据,包含http参数和数据(数据格式是HTML,CSS,协议是TLS、HTTP等),然后发给传输层;

  传输层接收封装后的数据,再封装一次,加上tcp头,变成tcp头、http data, 然后发给网络层;

  网络层接收封装后的数据,再封装一次,加上ip头,变成ip头、tcp头、http data,然后发给数据数据链路层;

  数据链路层接收封装后的数据,再封装一次,加上以太网头,变成ethernet头、ip头、tcp头、 http data,通过物理层对客户端浏览器进行响应。

  这样,web服务端算是完成了一次响应。【详见OSI模型】

技术分享

  python内置了一个WSGI服务器(Web Server Gateway Interface),这个模块就是wigiref。它封装了对tcp、http请求和响应的操作。它负责处理socket的接口(封装了socket对象和准备过程(bind,listen等)),把请求信息(请求头和请求体)封装成键值对的对象,并可以方便地设置响应头和返回请求体。下面通过一个wsgi内置的写一个 web应用来加深理解wsg。i

  step1:WSGI的environ和return

技术分享
from wsgiref.simple_server import make_server

def application(environ, start_response):
    for key, value in environ.items():
        print(key, value)
    # 响应头,告诉浏览器响应的内容是什么格式
    start_response(200 OK, [(Content-Type, text/html)])
    return [b<h1>Hello, web!</h1>]    # 响应体

# make_server是一个http对象
httpd = make_server(‘‘, 8080, application)
print(Serving HTTP on port 8000 ...)

# 开始监听HTTP请求:
httpd.serve_forever()

‘‘‘
application()就是符合wSGI标准的一个HTTP处理函数,它接收两个参数:
    environ:一个包含所有HTTP请求信息的dict对象;
    start_response:一个发送HTTP响应的函数;
在applicaiton()函数中调用start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)]),就发送了HTTP响应的Header.
start_response()函数接收两个参数:
    一个是HTTP响应码
    一个是一组list表示的HTTP Header,每个Header用一个包含两个str的tuple表示.
    通常会把Content-Type头发送给浏览器,其他很多常用的HTTP Header也应该发送。
然后,函数的返回值b‘<h1>Hello, web!</h1>‘将作为HTTP响应的Body发送给浏览器.
有了WSGI,我们关心的就是如何从environ中拿到解析好的请求信息,从而写自己的处理逻辑了。
‘‘‘
WSGI的simple_server
技术分享
ALLUSERSPROFILE C:\ProgramData
APPDATA C:\Users\admin\AppData\Roaming
COMMONPROGRAMFILES C:\Program Files\Common Files
COMMONPROGRAMFILES(X86) C:\Program Files (x86)\Common Files
COMMONPROGRAMW6432 C:\Program Files\Common Files
COMPUTERNAME DESKTOP-ABISCDM
COMSPEC C:\WINDOWS\system32\cmd.exe
FPS_BROWSER_APP_PROFILE_STRING Internet Explorer
FPS_BROWSER_USER_PROFILE_STRING Default
HOMEDRIVE C:
HOMEPATH \Users\admin
LOCALAPPDATA C:\Users\admin\AppData\Local
LOGONSERVER \\DESKTOP-ABISCDM
MOZ_PLUGIN_PATH C:\其它软件\福昕阅读器\Foxit Reader\pluginsNUMBER_OF_PROCESSORS 4
ONEDRIVE C:\Users\admin\OneDrive
OS Windows_NT
PATH C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\MySQL\MySQL Utilities 1.6\;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\Zpythons\python36\Scripts\;C:\Zpythons\python36\;C:\Users\admin\AppData\Local\Microsoft\WindowsApps;
PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE AMD64
PROCESSOR_IDENTIFIER Intel64 Family 6 Model 142 Stepping 9, GenuineIntel
PROCESSOR_LEVEL 6
PROCESSOR_REVISION 8e09
PROGRAMDATA C:\ProgramData
PROGRAMFILES C:\Program Files
PROGRAMFILES(X86) C:\Program Files (x86)
PROGRAMW6432 C:\Program Files
PSMODULEPATH C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
PT5HOME C:\Cisco Packet Tracer 6.0
PT6HOME C:\Cisco Packet Tracer 6.0
PUBLIC C:\Users\Public
PYCHARM_HOSTED 1
PYTHONIOENCODING UTF-8
PYTHONPATH C:\Users\admin\Desktop\pythonNote\网络编程基础
PYTHONUNBUFFERED 1
SESSIONNAME Console
SYSTEMDRIVE C:
SYSTEMROOT C:\WINDOWS
TEMP C:\Users\admin\AppData\Local\Temp
TMP C:\Users\admin\AppData\Local\Temp
USERDOMAIN DESKTOP-ABISCDM
USERDOMAIN_ROAMINGPROFILE DESKTOP-ABISCDM
USERNAME admin
USERPROFILE C:\Users\admin
VS140COMNTOOLS C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\ToolsWINDIR C:\WINDOWS
SERVER_NAME DESKTOP-ABISCDM
GATEWAY_INTERFACE CGI/1.1
SERVER_PORT 8080
REMOTE_HOST 
CONTENT_LENGTH 
SCRIPT_NAME 
SERVER_PROTOCOL HTTP/1.1
SERVER_SOFTWARE WSGIServer/0.2
REQUEST_METHOD GET
PATH_INFO /alex
QUERY_STRING 
REMOTE_ADDR 127.0.0.1
CONTENT_TYPE text/plain
HTTP_HOST 127.0.0.1:8080
HTTP_USER_AGENT Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
HTTP_ACCEPT_LANGUAGE zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
HTTP_ACCEPT_ENCODING gzip, deflate
HTTP_COOKIE csrftoken=b2CBBrcSjnRT91jAB1KJzUWphnWB28UiLrHQuECAsv6vWPy4vGWIsHXkRHWh0gTy; sessionid=y4l1ybo6t01nhpqsjkh6fyqm44blinca
HTTP_CONNECTION keep-alive
HTTP_UPGRADE_INSECURE_REQUESTS 1
HTTP_CACHE_CONTROL max-age=0
wsgi.input <_io.BufferedReader name=748>
wsgi.errors <_io.TextIOWrapper name=<stderr> mode=w encoding=UTF-8>
wsgi.version (1, 0)
wsgi.run_once False
wsgi.url_scheme http
wsgi.multithread True
wsgi.multiprocess False
wsgi.file_wrapper <class wsgiref.util.FileWrapper>
查看environ封装的所有信息

  step2:根据浏览器输入的url,进行逻辑处理:

技术分享
from wsgiref.simple_server import make_server

def application(environ, start_response):

    # 响应头,告诉浏览器响应的内容是什么格式
    start_response(200 OK, [(Content-Type, text/html)])
    # message = start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)])
    # print(message)

    # 打印所有的请求信息
    for key, value in environ.items():
        print(key, value)

    # 从environ中拿到url,键名是‘PATH_INFO‘,然后做一个处理:
    path = environ[PATH_INFO]
    f1 = open(index1.html, rb)
    data1 = f1.read()    #当前文件夹下创建index1.html和index2.html,内容随便写.
    f2 = open(index2.html, rb)
    data2 = f2.read()
    if path == /yuan:
        return [data1]
    elif path == /alex:
        return [data2]
    else:
        return [b<h1>Hello, web!</h1>]    # 响应体

# make_server是一个http对象
httpd = make_server(‘‘, 8080, application)
print(Serving HTTP on port 8000 ...)

# 开始监听HTTP请求:
httpd.serve_forever()
接收请求并进行逻辑处理

  step3:把上述逻辑处理进行解耦:

技术分享
from wsgiref.simple_server import make_server

def f1():
    f1 = open(index1.html, rb)
    return [f1.read()]
def f2():
    f2 = open(index2.html, rb)
    return [f2.read()]

def application(environ, start_response):
    start_response(200 OK, [(Content-Type, text/html)])
    path = environ[PATH_INFO]

    if path == /yuan:
        return f1()
    elif path == /alex:
        return f2()
    else:
        return [b<h1>Hello, web!</h1>]

httpd = make_server(‘‘, 8080, application)
print(Serving HTTP on port 8000 ...)

httpd.serve_forever()
解耦式写法

  step4:接近MVC的升级式写法:

技术分享
import time
from wsgiref.simple_server import make_server

def f1(request):
    print(request[QUERY_STRING])
    f1 = open(index1.html, rb)
    return [f1.read()]

def f2(request):
    f2 = open(index2.html, rb)
    return [f2.read()]

def f3(request):
    f3 = open(index3.html, rb)
    localtime = time.strftime(%Y-%m-%d %X,time.localtime())
    html = f3.read()
    print(html)
    html = str(html, utf8).replace(!time!, str(localtime))
    return [html.encode(utf8)]

def routes():
    urlpatterns = [
        (/yuan, f1),
        (/alex, f2),
        (/cur_time, f3),
    ]
    return urlpatterns

def application(environ, start_response):
    path = environ[PATH_INFO]
    start_response(200 OK, [(Contentt-Type, text/html)])

    urlpatterns = routes()
    func = None
    for item in urlpatterns:
        if item[0] == path:
            func = item[1]
            break

    if func:
        return func(environ)
    else:
        return [<h2>404</h2>.encode(utf8)]

httpd = make_server(‘‘, 8001, application)
print(Serving HTTP on port 8001 ...)

httpd.serve_forever()

# 在浏览器中输入localhost:8001/yuan,或/alex,或/cur_time,或一个不存在的url地址

‘‘‘
html=b‘<!DOCTYPE html>\r\n<html lang="en">\r\n<head>\r\n    <meta charset="UTF-8">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<h2>!time!</h2>\r\n</body>\r\n</html>‘
要点一:
    f3中的html,只写了个h2标签,里面写了!time!这个单词。
    f3跟f1,f2的不同之处在于,它对html进行了修改操作(访问一次,打印一次当前时间戳)。
    假如定义!time!是一个固定的“语言”,像!vector!,!func!等,都作为“自定义”的python处理方式,那么就可以识别该操作符,然后进行处理。
    django定义{{ 变量/函数 }} 和{% 变量/函数/简单循环 %},来与html进行交互。
    
    它扩展为django中的render功能,能够支持对html文件传入参数。以及templatetags,用来在后端给html增加一些功能。
    
要点二:
    rountes函数:在list列表中存放每个url和相应的处理函数的tuple,绑定url和处理函数。
    每当有url访问,就对这个List对象进行遍历,找到处理函数就返回相应的结果,没找到就返回一个404错误。
    它相当于django中的url.py文件。
    
    applicattion()函数中写了多行代码来处理url和func的映射关系。
    在django中,它被封装了起来, 用户只需要在urlpatterns中添加url和处理函数。然后在views中写处理逻辑就行了。

‘‘‘
升级版写法

  如果把f1(),f2(),f3()写在一个models.py中,把routes写进一个urls.py中,把application写在controller.py中,把html写在一个view文件夹下。那就构成了web框架中著名的MVC模式。

三、web框架的MVC模式和django的MTV模式

  大部分开发语言中都有MVC框架,MVC框架的核心思想是:解耦。上面WSGI的升级版写法已经体现了这个特点。

  技术分享

 

  所谓MVC,就是指model、view、controller。m主要用于对数据库层的封装,v主要向用户展示结果,c是核心,用于处理请求、获取数据、返回结果。

  django是一款python的web开发框架,使用了MVT模式,它本质上与MVC模式没什么差别。MVT是model, template, view。m负责业务对象与数据库的对象(ORM), template负责如何把页面展示给用户,view负责业务逻辑,并在适当的时候调用model和template。此外,还有一个url分发器,它的作用是将一个个url页面请求分发给不同的view处理。

  重新解释一遍:model负责与数据库交互,view是核心,负责接收请求,获取数据,返回结果,template负责呈现内容到浏览器。

技术分享

 

技术分享
http://www.cnblogs.com/yuanchenqi/articles/6083427.html
# 老男孩python全栈工程师培训著名讲师苑昊博客
原文链接地址

 

django基础一:web、wsgi、mvc、mtv

标签:title   编码   ati   tle   udp协议   udp   串口助手   arch   开发   

原文地址:http://www.cnblogs.com/kuaizifeng/p/7618117.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!