Python 网络服务相关 杂记
個(gè)人所有文章整理在此篇,將陸續(xù)更新收錄:知無涯,行者之路莫言終(我的編程之路)
本文雜記了下面一些點(diǎn)
[1].Python的原生版Socket [2].python自帶的模塊:`wsgiref`的簡(jiǎn)單使用 [3].Python和Idea的愛恨情,pip裝了模塊但不能用,或飄紅了但能用 [4].隨手一說 jinja2 [5].django的簡(jiǎn)單介紹 [6].django中使用MySQL數(shù)據(jù)庫(kù) 復(fù)制代碼一、先看看Socket吧
客戶端 通過url 查詢IP和端口號(hào) 建立TCP/IP連接 將請(qǐng)求信息及數(shù)據(jù) 發(fā)送給服務(wù)端 并制定資源地址 服務(wù)端 接收請(qǐng)求及數(shù)據(jù) 根據(jù)資源地址 進(jìn)行處理 返回響應(yīng)信息及數(shù)據(jù) 給客戶端 復(fù)制代碼1.用瀏覽器訪問服務(wù)
socket.accept()方法會(huì)阻塞下面語句的繼續(xù),當(dāng)有連接時(shí)便會(huì)接觸阻塞
import socketif __name__ == '__main__':socket = socket.socket() # 生成socket對(duì)象socket.bind(("127.0.0.1", 8089)) # 綁定IP和端口socket.listen() # 監(jiān)聽conn, addr = socket.accept() # 獲取連接 -- 阻塞方法data = conn.recv(1024 * 8) # 接收客戶端數(shù)據(jù)conn.send(b"HTTP/1.0 200\r\n") # 響應(yīng)頭conn.send(b"\r\n") # 空行conn.send(b"hello from server") # 響應(yīng)數(shù)據(jù)print(data)socket.close()conn.close() 復(fù)制代碼抓一下包,看一下請(qǐng)求與響應(yīng)
|--- 抓包獲取的客戶端請(qǐng)求數(shù)據(jù)----------------- GET http://127.0.0.1:8089/ HTTP/1.1 Host: 127.0.0.1:8089 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9|--- 抓包獲取的服務(wù)端響應(yīng)數(shù)據(jù)--------------------- HTTP/1.0 200hello from server 復(fù)制代碼2.服務(wù)端如何發(fā)送一個(gè)靜態(tài)頁面給客戶端
不作處理返回原樣,也就是整個(gè)html的文件字符
import os import socketif __name__ == '__main__':socket = socket.socket() # 生成socket對(duì)象socket.bind(("127.0.0.1", 8089)) # 綁定IP和端口socket.listen() # 監(jiān)聽path = os.path.dirname(__file__) + "/lizi.html"//讀取文件 存儲(chǔ)在str變量f = open(path, encoding="utf-8")str = ''for line in iter(f): # 迭代遍歷str += lineconn, addr = socket.accept() # 獲取連接 -- 阻塞方法data = conn.recv(1024 * 8) # 接收客戶端數(shù)據(jù)conn.send(b"HTTP/1.0 200\r\n") # 響應(yīng)頭conn.send(b"\r\n") # 空行conn.send(str.encode()) # 響應(yīng)數(shù)據(jù)print(data)socket.close()conn.close() 復(fù)制代碼如果要告訴瀏覽器這是html ,需要一個(gè)響應(yīng)頭 : content-type:text/html; charset=utf-8
就這么簡(jiǎn)單,然后一個(gè)頁面就能被瀏覽器渲染了,所以說一個(gè)網(wǎng)站運(yùn)行起來倒不是什么費(fèi)勁的事,但優(yōu)化是要來老命...
3.根據(jù)url來控制顯示文字
lizi.html 是靜態(tài)界面,如何實(shí)現(xiàn)動(dòng)態(tài)效果? 服務(wù)端可以對(duì)靜態(tài)界面進(jìn)行加工再返還給服務(wù)端
import os import socket if __name__ == '__main__':socket = socket.socket() # 生成socket對(duì)象socket.bind(("127.0.0.1", 8089)) # 綁定IP和端口socket.listen() # 監(jiān)聽path = os.path.dirname(__file__) + "/lizi.html"f = open(path, encoding="utf-8")res = ''for line in iter(f): # 迭代遍歷res += lineconn, addr = socket.accept() # 獲取連接 -- 阻塞方法data = conn.recv(1024 * 8) # 接收客戶端數(shù)據(jù)# 服務(wù)器對(duì)客戶端的請(qǐng)求數(shù)據(jù)進(jìn)行加工,控制轉(zhuǎn)換后發(fā)送給客戶端data = str(data, encoding="utf-8")li = data.split("\r\n")firstLine = li[0]liFirstLine = firstLine.split(" ")param = liFirstLine[1].replace("/", '')res = res.replace("張風(fēng)捷特烈", param)conn.send(b"HTTP/1.0 200\r\n") # 響應(yīng)頭conn.send(b"content-type:text/html; charset=utf-8\r\n") # 響應(yīng)頭conn.send(b"\r\n") # 空行conn.send(res.encode()) # 響應(yīng)數(shù)據(jù)socket.close()conn.close() 復(fù)制代碼二、服務(wù)小框架
如果說上面的是遠(yuǎn)古時(shí)期的時(shí)期時(shí)代,只能用打磨的石頭當(dāng)武器,隨著社會(huì)發(fā)展,冷兵器也將到來
python服務(wù)端的框架就相當(dāng)于刀劍的江湖
1.python自帶的模塊:wsgiref
負(fù)責(zé)與客戶端的socket通信,用起來比自己寫的爽一些
import os from wsgiref.simple_server import make_server def readfile(path):with open(path, "rb") as f:return f.read()def lizi(src):path = os.path.dirname(__file__) + srcreturn readfile(path)def runServer(evn, rep):rep('200 OK', [('Content-Type', 'text/html; charset=utf-8')])url = evn['PATH_INFO']return [lizi(url)] # 注意這里返回列表...掉坑了if __name__ == '__main__':httpd = make_server('127.0.0.1', 8089, runServer)httpd.serve_forever() 復(fù)制代碼2.關(guān)于Python和IDEA
也許是python版本換了之后弄的挺亂,pip裝的包竟然IDEA竟然找不到...
看一下Python的配置classpath 里有好多東西,刪了會(huì)怎樣?
- 然后我就全刪了
結(jié)果print 函數(shù)都飄紅了,神奇的是一點(diǎn)擊能正常運(yùn)行。也就是 classpath 里找不到print 函數(shù)
但Python運(yùn)行環(huán)境還是在那的,雖然飄紅但能運(yùn)行。怎么讓它不飄紅 classpath 加回去唄
- 添加stdlib的classpath
- 如果現(xiàn)在使用外來包會(huì)怎么樣
拿Jinja2來看,首先確保安裝了它
J:\Python>pip freeze cycler==0.10.0 Django==2.1.7 et-xmlfile==1.0.1 jdcal==1.4 Jinja2==2.10 ... 復(fù)制代碼3. jinja2的使用
還是飄紅但能用
---->[net\date.html]---------模板------- <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body>now time :{{time}}<ul>{% for name in names %}<li>{{name}}</li>{% endfor %} </ul> </body> </html>---->[net\ServerLever5.py]---------服務(wù)代碼------- import time from jinja2 import Template from wsgiref.simple_server import make_serverdef date():with open('date.html', "r") as f:res = f.read()tpl = Template(res)dest = tpl.render({"time": getTime(), "names": ["捷特", "龍少", "巫纓"]})return [bytes(dest, encoding="utf8")]def getTime():now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))return nowdef runServer(evn, rep):rep('200 OK', [('Content-Type', 'text/html; charset=utf-8')])return date() if __name__ == '__main__':httpd = make_server('127.0.0.1', 8089, runServer)httpd.serve_forever() 復(fù)制代碼4.解決方法
飄紅看起來礙眼,而且沒提示,怎么辦?
查看H:\\PythonDK\\lib\\site-packages 將他加到classpath
OK 不飄紅,有提示,能運(yùn)行 繼續(xù)開心地敲代碼吧,如果哪飄紅就找找classpath在哪
三、django框架
1.安裝框架:django
安裝依賴 pip3 install django
J:\Python\NetAll>pip3 install django Collecting djangoDownloading https://files.pythonhosted.org/packages/c7/87/fbd666c4f87591ae25b7bb374298e8629816e87193c4099d3608ef11fab9/Django-2.1.7-py3-none-any.whl (7.3MB)100% |████████████████████████████████| 7.3MB 521kB/s Requirement already satisfied: pytz in h:\pythondk\lib\site-packages (from django) (2018.9) Installing collected packages: django Successfully installed django-2.1.7|--- 控制行 ( 如果錯(cuò)誤:配置環(huán)境變量 python目錄\Scripts ) C:\Users\Administrator>django-adminType 'django-admin help <subcommand>' for help on a specific subcommand. Available subcommands: [django]checkcompilemessagescreatecachetabledbshelldiffsettingsdumpdataflushinspectdbloaddatamakemessagesmakemigrationsmigraterunserversendtestemailshellshowmigrationssqlflushsqlmigratesqlsequenceresetsquashmigrationsstartappstartprojecttesttestserver 復(fù)制代碼2.創(chuàng)建一個(gè)項(xiàng)目
django-admin startproject toly_web 復(fù)制代碼3.最簡(jiǎn)單的兩個(gè)頁面
先直接在urls.py里測(cè)試一下django的作用, 開啟服務(wù):python manage.py runserver 8000
---->[toly_web/urls.py]-------------------- from django.shortcuts import HttpResponse from django.urls import pathdef lizi(req): # req--請(qǐng)求的封裝對(duì)象return HttpResponse("Hello World From Server -- lizi") def toly(req): # req--請(qǐng)求的封裝對(duì)象return HttpResponse("Hello World From Server -- toly")# 路徑和函數(shù)的映射集 urlpatterns = [path('toly/', toly),path('lizi/', lizi), ] 復(fù)制代碼4.返回html頁面
這里新建一個(gè)templates文件夾盛放html頁面
def readfile(path):with open("./templates/" + path, "r", encoding="utf-8") as f:return f.read()def lizi(req): # req--請(qǐng)求的封裝對(duì)象return HttpResponse(readfile('lizi.html')) 復(fù)制代碼5.配置templates文件夾
當(dāng)然上那樣寫也可以,不過不方便,還要自己讀文件,settings中有TEMPLATES文件夾的設(shè)置
配置一下就可以用django內(nèi)置的文件渲染函數(shù)
- 使用起來很簡(jiǎn)單
6.django中使用靜態(tài)文件
由于Html需要引入靜態(tài)文件(js,css,圖片,文件等),最好也配置一個(gè)靜態(tài)文件的文件夾
springboot,react等框架,一般來說都是static文件夾盛放靜態(tài)文件,這個(gè)沒必要標(biāo)新立異...
7.分文件處理
也就是將處理邏輯和url分文件寫,控制職責(zé)
---->[toly_web/urls.py]-------------------------- from django.urls import path from toly_web.pagers import toly, lizi, photo# 路徑和函數(shù)的映射集 urlpatterns = [path('toly/', toly),path('lizi/', lizi),path('photo/', photo), ]---->[toly_web/pagers.py]-------------------------- from django.shortcuts import HttpResponse, renderdef readfile(path):with open("./templates/" + path, "r", encoding="utf-8") as f:return f.read()def lizi(req): # req--請(qǐng)求的封裝對(duì)象return HttpResponse(readfile('lizi.html'))def photo(req): # req--請(qǐng)求的封裝對(duì)象return render(req, 'photo.html')def toly(req): # req--請(qǐng)求的封裝對(duì)象return HttpResponse("Hello World From Server -- toly") 復(fù)制代碼簡(jiǎn)單來說django幫我們解決了客戶端和服務(wù)端的通信問題,和服務(wù)端的開啟為題
我們需要關(guān)注的是業(yè)務(wù)的處理邏輯和路徑的指定,網(wǎng)絡(luò)訪問框架基本都是這個(gè)套路
四、django中的表單和App
1.做一個(gè)注冊(cè)頁面
代碼就不貼了,不想寫樣式的弄四個(gè)框也行
|--- url 指向 : http://127.0.0.1:8000/register/ |--- 提交跳轉(zhuǎn)路徑 :http://127.0.0.1:8000/add_user/ 復(fù)制代碼會(huì)出現(xiàn)下面的錯(cuò)誤,將setting的這句話注釋起來即可
2.響應(yīng)的方法add_user
如何獲取用戶的輸入數(shù)據(jù)
def add_user(req):post = req.POSTprint(post)return HttpResponse(post)|--- 結(jié)果是一個(gè)QueryDict <QueryDict: {'username': ['toly'], 'email': ['1981462002@qq.com'], 'pwd': ['123'], 'pwd_conform': ['123']}>|--- 獲取用戶輸入數(shù)據(jù) ------------------------------- from django.http import HttpResponse def add_user(req):post = req.POSTprint(post)username = req.POST.get('username', None)email = req.POST.get('email', None)pwd = req.POST.get('pwd', None)pwd_conform = req.POST.get('pwd_conform', None)res = ' username= ' + username + ' \r\nemail= ' + email + ' \r\npwd= ' + pwd + '\r\npwd_conform=' + pwd_conformreturn HttpResponse(res) 復(fù)制代碼3.字符占位 與重定向
django和 jinja2里的用法差不多 :html里-- {{變量名}} 使用,如下
def add_user(req):post = req.POSTprint(post)username = req.POST.get('username', None)email = req.POST.get('email', None)pwd = req.POST.get('pwd', None)pwd_conform = req.POST.get('pwd_conform', None)if pwd == pwd_conform:# return render(req, "photo.html")return redirect("/photo") # 重定向else:return render(req, "register.html", {'err': "兩次密碼不一致", "username": username, "email": email})復(fù)制代碼- 服務(wù)失敗
- 服務(wù)成功
4.創(chuàng)建App
做安卓的對(duì)app的理解會(huì)深很多
記得末尾不要加; --- MySQL敲多了容易敲錯(cuò)...
5.配置app
相當(dāng)于安裝吧...
# Application definition # app 相關(guān)配置 --- 安裝-------------- INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','IGallery.apps.IgalleryConfig', # 全類名 ] 復(fù)制代碼6.使用app
將頁面放入相應(yīng)資源中,在views里寫函數(shù)
---->[IGallery/views.py]------------------------------- from django.shortcuts import renderdef gallery(req): return render(req, '3dg.html')|-- 添加路由 ------------- from IGallery import views path('gallery/', views.gallery), 復(fù)制代碼五、django 的 ORM 操作
1.重點(diǎn)來了,要玩數(shù)據(jù)庫(kù)了
ORM Object Relational Mapping 感覺有點(diǎn)MyBatis的感覺
# settings配置 數(shù)據(jù)庫(kù)相關(guān) DATABASES = {'default': {# 'ENGINE': 'django.db.backends.sqlite3', # 哇,sqlite3# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),'ENGINE': 'django.db.backends.mysql', # 用mysql'HOST': '127.0.0.1', # ip'PORT': '3306', # 端口'NAME': 'datatype', # 數(shù)據(jù)庫(kù)名'USER': 'root', # 用戶名'PASSWORD': 'xxxxxx', # 密碼} } 復(fù)制代碼2.連接數(shù)據(jù)庫(kù) : 安裝 pymysql
---->[toly_web/__init__.py]----------------- import pymysql # 用pymysql代替MySQLdb pymysql.install_as_MySQLdb() 復(fù)制代碼3.創(chuàng)建表
---->[IGallery/models.py]---------------創(chuàng)建實(shí)體類----------- class PicUser(models.Model):id = models.AutoField(primary_key=True) # 自增長(zhǎng)主鍵username = models.CharField(null=False, max_length=20) # 非空用戶名password = models.CharField(null=False, max_length=24) # 非空密碼|--- 執(zhí)行命令 ---------------------校驗(yàn)改動(dòng)-------------- J:\Python\toly_web>python manage.py makemigrations Migrations for 'IGallery':IGallery\migrations\0001_initial.py- Create model PicUser|--- 執(zhí)行命令 ---------------------執(zhí)行改動(dòng)--------------- J:\Python\toly_web>python manage.py migrate Operations to perform:Apply all migrations: IGallery, admin, auth, contenttypes, sessions Running migrations:Applying IGallery.0001_initial... OKApplying contenttypes.0001_initial... OKApplying auth.0001_initial... OKApplying admin.0001_initial... OKApplying admin.0002_logentry_remove_auto_add... OKApplying admin.0003_logentry_add_action_flag_choices... OKApplying contenttypes.0002_remove_content_type_name... OKApplying auth.0002_alter_permission_name_max_length... OKApplying auth.0003_alter_user_email_max_length... OKApplying auth.0004_alter_user_username_opts... OKApplying auth.0005_alter_user_last_login_null... OKApplying auth.0006_require_contenttypes_0002... OKApplying auth.0007_alter_validators_add_error_messages... OKApplying auth.0008_alter_user_username_max_length... OKApplying auth.0009_alter_user_last_name_max_length... OKApplying sessions.0001_initial... OK|--- mysql查看創(chuàng)建的表 --------------------------- mysql> SHOW TABLES; +----------------------------+ | Tables_in_datatype | +----------------------------+ | auth_group | | auth_group_permissions | | auth_permission | | auth_user | | auth_user_groups | | auth_user_user_permissions | | django_admin_log | | django_content_type | | django_migrations | | django_session | | igallery_picuser | +----------------------------+mysql> DESC igallery_picuser; +----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | username | varchar(20) | NO | | NULL | | | password | varchar(24) | NO | | NULL | | +----------+-------------+------+-----+---------+----------------+ 復(fù)制代碼4.插入數(shù)據(jù)
還用剛才的注冊(cè)表單
def add_user(req):...if pwd == pwd_conform:PicUser.objects.create(username=username, password=pwd) # 插入數(shù)據(jù)...else:... 復(fù)制代碼5.獲取數(shù)據(jù)
def list_user(req):res = PicUser.objects.all() # 獲取對(duì)象 [o1,o2,03]return render(req, "user_list.html", {"user_list": res})|--- html 表格 -------------------------- <div class="container"> <table class="table table-striped table-bordered col-sm-8"><thead><tr><th>id值</th><th>用戶名</th><th>密碼</th></tr></thead><tbody>{% for user in user_list %}<tr><td>{{ user.id }}</td><td>{{ user.username }}</td><td>{{ user.password }}</td></tr>{% endfor %}</tbody> </table> 復(fù)制代碼OK ,本文挺雜亂的,基本的服務(wù)端框架也就這樣,PHP , Java的SpringBoot ,React ,Vue
核心都是模板填充數(shù)據(jù),或只提供數(shù)據(jù)服務(wù),整體梳理一下,細(xì)節(jié)方面,再說...
總結(jié)
以上是生活随笔為你收集整理的Python 网络服务相关 杂记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP下的浮点运算不准的解决办法
- 下一篇: Nginx服务器编译添加SSL模块