算機(jī)網(wǎng)絡(luò)課設(shè)實(shí)戰(zhàn):精品課程網(wǎng)站從部署到排障全記錄)
簡(jiǎn)介計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)中的精品課程網(wǎng)站建設(shè)方案主要面向高校網(wǎng)絡(luò)工程、計(jì)算機(jī)相關(guān)專業(yè)學(xué)生用于完成課程設(shè)計(jì)或畢業(yè)設(shè)計(jì)。資源圍繞一個(gè)可接入互聯(lián)網(wǎng)的精品課程網(wǎng)站展開要求支持一百個(gè)以上站點(diǎn)網(wǎng)絡(luò)內(nèi)部采用千兆主干、百兆到桌面的結(jié)構(gòu)并需劃分至少四個(gè)子網(wǎng)同時(shí)提供域名解析、動(dòng)態(tài)地址分配、網(wǎng)頁服務(wù)、文件傳輸?shù)确?wù)整體覆蓋網(wǎng)絡(luò)拓?fù)?、地址?guī)劃、服務(wù)器部署和主頁編寫等關(guān)鍵環(huán)節(jié)。包內(nèi)共有三個(gè)文件核心為兩份文檔和一份網(wǎng)頁源碼文檔用于撰寫設(shè)計(jì)思路、方案說明與配置步驟網(wǎng)頁源碼展示基礎(chǔ)前端頁面實(shí)現(xiàn)整個(gè)壓縮包約 574KB輕量便于查閱。當(dāng)前已有八百六十人學(xué)習(xí)瀏覽適合需要參考完整設(shè)計(jì)流程、網(wǎng)絡(luò)服務(wù)配置方法及報(bào)告寫法的同學(xué)。借助這份資源讀者能掌握從需求分析到子網(wǎng)劃分、服務(wù)器角色配置再到網(wǎng)絡(luò)設(shè)計(jì)與網(wǎng)頁實(shí)現(xiàn)結(jié)合的完整方法形成可提交的課程設(shè)計(jì)成果。 每年計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)繞不開的一個(gè)題目就是精品課程網(wǎng)站設(shè)計(jì)。表面上看它跟普通網(wǎng)站開發(fā)沒什么區(qū)別無非是放課程簡(jiǎn)介、課件、教學(xué)視頻再加個(gè)在線測(cè)試和留言板。但真正做下來你會(huì)發(fā)現(xiàn)這個(gè)題目把網(wǎng)絡(luò)原理里的協(xié)議、地址、服務(wù)、安全全調(diào)動(dòng)起來了HTTP是應(yīng)用層TCP三次握手是傳輸層IP地址和路由是網(wǎng)絡(luò)層DHCP和DNS又是怎么配合的全都能在項(xiàng)目里找到對(duì)應(yīng)物。這篇文章記錄我自己完整做一遍精品課程網(wǎng)站的過程包括需求拆解、技術(shù)選型、頁面實(shí)現(xiàn)、局域網(wǎng)部署以及調(diào)試網(wǎng)絡(luò)時(shí)踩過的各種坑。正在準(zhǔn)備課設(shè)、或者想把網(wǎng)絡(luò)知識(shí)和Web開發(fā)串起來的人都值得看一遍。1. 項(xiàng)目目標(biāo)與需求拆解1.1 這個(gè)課設(shè)真正要驗(yàn)收什么很多同學(xué)拿到“精品課程網(wǎng)站設(shè)計(jì)”這個(gè)題第一反應(yīng)是套一個(gè)現(xiàn)成的CMS模板換個(gè)課程名就交差。但如果是計(jì)算機(jī)網(wǎng)絡(luò)課程的課設(shè)題目里的“網(wǎng)絡(luò)”兩個(gè)字才是關(guān)鍵得分點(diǎn)。老師想看到的不是Bootstrap做出多漂亮的首頁而是你能把下面這幾件事講明白網(wǎng)站是怎么部署到服務(wù)器上的客戶端通過什么協(xié)議、什么地址訪問到它在局域網(wǎng)里怎么規(guī)劃IP域名是怎么解析的如果訪問出現(xiàn)問題你能不能定位到是網(wǎng)絡(luò)層、傳輸層還是應(yīng)用層的故障。我這次給自己的驗(yàn)收標(biāo)準(zhǔn)是一臺(tái)Ubuntu服務(wù)器一臺(tái)普通交換機(jī)幾臺(tái)客戶機(jī)搭一個(gè)小型局域網(wǎng)。服務(wù)器上跑課程網(wǎng)站所有終端通過IP地址和域名都能訪問。站在用戶角度需要課程介紹、教學(xué)大綱、課件下載、視頻點(diǎn)播、在線測(cè)試、留言板這些功能缺一個(gè)都不算完整。站在網(wǎng)絡(luò)角度需要能看到DHCP分配地址的過程能通過抓包看到HTTP請(qǐng)求三次握手能在安全設(shè)備日志里排查異常訪問。兩條線都走通了課設(shè)才算真正完成。1.2 技術(shù)選型按課設(shè)場(chǎng)景取舍課設(shè)不是企業(yè)項(xiàng)目不需要微服務(wù)也不需要前后端分離重點(diǎn)是把原理打通。我選了這套組合模塊我使用的方案為什么這么選前端頁面HTML CSS 原生JavaScript不用框架演示時(shí)容易解釋頁面加載流程后端邏輯Python Flask路由和HTTP方法非常直觀代碼量少數(shù)據(jù)庫MySQL 8.0課程常見能體現(xiàn)傳統(tǒng)關(guān)系型庫的配置過程Web服務(wù)器Nginx反向代理靜態(tài)資源和動(dòng)態(tài)請(qǐng)求配置清晰網(wǎng)絡(luò)環(huán)境VMware虛擬機(jī) 真實(shí)家用路由器既能模擬也能真機(jī)聯(lián)調(diào)兩端都覆蓋抓包工具Wireshark / tcpdump課堂演示網(wǎng)絡(luò)層分析的標(biāo)配Flask 開發(fā)服務(wù)器雖然也能跑但它只有一個(gè)進(jìn)程高并發(fā)弱而且老師一眼就知道你沒做生產(chǎn)環(huán)境部署。用 Nginx 加 uWSGI 跑 Flask才符合“網(wǎng)絡(luò)服務(wù)”這個(gè)課設(shè)題目。前端我不建議上 React/Vue因?yàn)檎n程設(shè)計(jì)的時(shí)間有限原生頁面配合 CSS 框架足夠還能把 URL 路由和 HTTP 請(qǐng)求講得更清楚。1.3 網(wǎng)絡(luò)環(huán)境設(shè)計(jì)總體思路網(wǎng)絡(luò)環(huán)境按一個(gè)小型校園單位來設(shè)計(jì)。服務(wù)器放在獨(dú)立網(wǎng)口IP 固定為 192.168.10.10/24。終端設(shè)備通過路由器DHCP自動(dòng)獲取 192.168.10.20 到 192.168.10.200 的地址。路由器就是網(wǎng)關(guān) 192.168.10.1同時(shí)承擔(dān)DNS轉(zhuǎn)發(fā)功能。這樣設(shè)計(jì)的好處是既能演示靜態(tài)IP配置也能演示DHCP協(xié)議交互還能讓學(xué)生終端隨意接入不需要手工設(shè)置網(wǎng)絡(luò)。這種網(wǎng)絡(luò)比單機(jī)虛擬機(jī)復(fù)雜的地方在于虛擬機(jī)的網(wǎng)絡(luò)模式要選“橋接模式”讓虛擬機(jī)直接掛到局域網(wǎng)里獲得和物理機(jī)同網(wǎng)段的地址。否則 NAT 模式下外部終端永遠(yuǎn)訪問不到它。首次做這個(gè)項(xiàng)目的人很容易忽視這點(diǎn)導(dǎo)致服務(wù)器只有本機(jī)才能打開網(wǎng)站。2. 網(wǎng)站核心功能與頁面實(shí)現(xiàn)2.1 功能模塊與URL路由精品課程網(wǎng)站我劃分成五個(gè)模塊首頁、課程資源、視頻教學(xué)、在線測(cè)試、留言板。每個(gè)模塊對(duì)應(yīng)一組 URL這其實(shí)就是 HTTP 應(yīng)用層的資源定位。Flask 后端代碼里路由直接映射函數(shù)調(diào)試的時(shí)候能看到 GET 和 POST 請(qǐng)求分別進(jìn)入哪里。from flask import Flask, render_template, request import os app Flask(__name__) app.route(/) def index(): return render_template(index.html) app.route(/course/ppt) def ppt_list(): files os.listdir(static/ppt) return render_template(ppt.html, filesfiles) app.route(/course/video) def video_list(): return render_template(video.html) app.route(/exam, methods[GET, POST]) def exam(): if request.method POST: # 接收答案并判分 return render_template(result.html, scorescore) return render_template(exam.html) app.route(/message, methods[GET, POST]) def message_board(): if request.method POST: # 寫數(shù)據(jù)庫 pass return render_template(message.html)注意一點(diǎn)路由中的/course/ppt不是文件系統(tǒng)路徑而是 Web 服務(wù)器映射出來的邏輯路徑。真正的文件放在/var/www/course/static/ppt下面Nginx 會(huì)把它映射成外部可訪問的 URL。這個(gè)映射關(guān)系是“網(wǎng)絡(luò)資源”和“本地文件”之間的橋梁很多人不關(guān)注但面試常問。2.2 課件與視頻資源的訪問策略課件和視頻是精品課程網(wǎng)站的大頭也是最容易拖垮服務(wù)器的地方。我的處理方式是課件文件統(tǒng)一放在static/ppt視頻文件放在static/video頁面通過遍歷目錄生成下載鏈接。這樣不用每次新增文件都改代碼也方便老師直接往目錄里丟素材。視頻播放不能用簡(jiǎn)單的a標(biāo)簽否則用戶必須下載完整文件才能看。用 HTML5 的video標(biāo)簽可以直接在線播放但服務(wù)器必須支持 Range 請(qǐng)求也就是 HTTP 分塊傳輸。Nginx 默認(rèn)支持 Range所以靜態(tài)視頻交給 Nginx 處理就行不要讓 Flask 去讀文件再返回。否則視頻播放會(huì)卡頓而且服務(wù)器內(nèi)存被瞬間占滿。我在 Nginx 里對(duì)這目錄做了單獨(dú)配置location /static/video/ { alias /var/www/course/static/video/; add_header Accept-Ranges bytes; }Range 請(qǐng)求是 HTTP 協(xié)議里非常典型的“斷點(diǎn)續(xù)傳”機(jī)制。瀏覽器播放視頻時(shí)會(huì)先請(qǐng)求前幾秒的數(shù)據(jù)播放到一半再請(qǐng)求下一段。你通過 Wireshark 抓包能看到請(qǐng)求頭里的Range: bytes0-1023響應(yīng)頭里有Content-Range。這個(gè)細(xì)節(jié)在課設(shè)答辯時(shí)講出來含金量很高。2.3 在線測(cè)試與留言板的實(shí)現(xiàn)在線測(cè)試我做了十個(gè)單選題題目放在一個(gè) JSON 文件里答案用 SHA256 哈希值存不直接明文寫答案防止學(xué)生查看源碼。用戶提交答案后后端逐題比對(duì)哈希值最后返回分?jǐn)?shù)。這種設(shè)計(jì)雖然比明文多寫幾行代碼但能體現(xiàn)你懂一點(diǎn)信息安全的思路。判斷題、多選題也能按同樣邏輯擴(kuò)展。留言板是典型的 POST 請(qǐng)求場(chǎng)景也是安全問題高發(fā)區(qū)。第一次寫的時(shí)候我直接拼接 SQL結(jié)果輸入一個(gè)單引號(hào)就把頁面打崩了。后面改成參數(shù)化查詢徹底解決 SQL 注入問題。建表語句如下CREATE TABLE message ( id INT AUTO_INCREMENT PRIMARY KEY, nickname VARCHAR(50) NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) DEFAULT CHARSETutf8mb4;注意這里特意指定utf8mb4不然留言里出現(xiàn)表情符號(hào)或者中文特殊字符保存后就是亂碼。字符集是新手最容易踩的坑頁面、數(shù)據(jù)庫、連接串三處編碼不統(tǒng)一中文數(shù)據(jù)就會(huì)變成“????”。我統(tǒng)一改成 UTF-8 后問題才徹底消失。這個(gè)坑看似是應(yīng)用層問題實(shí)際上和 TCP 傳輸?shù)淖止?jié)流顯示有關(guān)也可以從編碼原理上跟面試官聊幾句。3. 網(wǎng)絡(luò)配置與服務(wù)器部署實(shí)戰(zhàn)3.1 IP地址和DHCP怎么配合局域網(wǎng)里服務(wù)器必須用靜態(tài) IP否則DHCP租約到期后地址變了所有客戶端都訪問不了網(wǎng)站。其他的教師機(jī)和學(xué)生終端用 DHCP 自動(dòng)獲取這樣任何設(shè)備接入局域網(wǎng)都能自動(dòng)獲得 IP、掩碼、網(wǎng)關(guān)和 DNS。這里有個(gè)容易混淆的點(diǎn)DHCP 不只是分配 IP它還可以下發(fā)網(wǎng)關(guān)和 DNS。所以只要路由器開了 DHCP客戶端瀏覽器就能正常解析域名并訪問外網(wǎng)。我在路由器上的配置是這樣的DHCP 地址池 192.168.10.100 到 192.168.10.200網(wǎng)關(guān) 192.168.10.1首選 DNS 用 223.5.5.5。服務(wù)器單獨(dú)保留 192.168.10.10不做 DHCP 分配。為了驗(yàn)證 DHCP 工作我打開客戶機(jī)的命令行用ipconfig /renew重新獲取地址然后用 Wireshark 抓 DHCP Discover、Offer、Request、ACK 四個(gè)包。這就是課設(shè)里最直接的“網(wǎng)絡(luò)協(xié)議可視化”素材。設(shè)備IP地址獲取方式用途W(wǎng)eb服務(wù)器192.168.10.10/24靜態(tài)配置跑Nginx、MySQL、Flask網(wǎng)關(guān)/路由器192.168.10.1/24固定DHCP、DNS轉(zhuǎn)發(fā)、NAT教師機(jī)192.168.10.100/24DHCP后臺(tái)維護(hù)學(xué)生終端192.168.10.x/24DHCP訪問課程網(wǎng)站3.2 域名解析從小處理解DNS如果只讓學(xué)生用 IP 訪問網(wǎng)站那 DNS 部分就沒法體現(xiàn)。我在內(nèi)網(wǎng)自己配了一個(gè)域名course.jingpin.local。最簡(jiǎn)單的方式是在每臺(tái)客戶機(jī)的 hosts 文件里寫一行192.168.10.10 course.jingpin.local這個(gè)方式能演示基本解析流程但只能逐臺(tái)配置。更接近真實(shí)場(chǎng)景的是用 dnsmasq 搭建內(nèi)網(wǎng) DNS 服務(wù)器然后讓路由器把 DNS 指向它。這樣所有客戶機(jī)只要 DHCP 拿到地址自動(dòng)就能解析域名。課程設(shè)計(jì)里能說清楚這兩種方式的區(qū)別就已經(jīng)超過了大部分同學(xué)。有了域名之后Nginx 里要配置虛擬主機(jī)。用不同的server_name區(qū)分不同站點(diǎn)這是 HTTP 請(qǐng)求頭里Host字段的應(yīng)用。配置片段如下server { listen 80; server_name course.jingpin.local; root /var/www/course; index index.html; location /static/ { alias /var/www/course/static/; } location / { include uwsgi_params; uwsgi_pass 127.0.0.1:3031; } }瀏覽器訪問http://course.jingpin.local時(shí)流程是先通過 DNS 或 hosts 解析域名得到 192.168.10.10然后向這個(gè) IP 發(fā)起 TCP 三次握手再發(fā)送 HTTP GET 請(qǐng)求Nginx 發(fā)現(xiàn)Host是course.jingpin.local就匹配到這個(gè) server 塊把請(qǐng)求轉(zhuǎn)發(fā)給 Flask。這個(gè)過程可以在瀏覽器開發(fā)者工具和 Wireshark 里完整看到答辯時(shí)照著這個(gè)順序講邏輯非常清晰。3.3 Web服務(wù)發(fā)布到局域網(wǎng)部署步驟整理成命令清單直接照著做就能跑通# 更新系統(tǒng)并安裝依賴 sudo apt update sudo apt install -y nginx mysql-server python3-pip pip3 install flask flask-sqlalchemy uwsgi # 啟動(dòng)數(shù)據(jù)庫并建庫 sudo systemctl start mysql sudo mysql -e CREATE DATABASE course DEFAULT CHARSET utf8mb4; # 把 Flask 項(xiàng)目放到指定目錄 sudo mkdir -p /var/www/course # 項(xiàng)目代碼復(fù)制到 /var/www/course 后配置 uwsgi uwsgi --socket 127.0.0.1:3031 --wsgi-file app.py --callable app --daemonize /var/log/course.log這里關(guān)鍵點(diǎn)是 Flask 啟動(dòng)時(shí)一定要監(jiān)聽所有網(wǎng)卡而不是默認(rèn)的 127.0.0.1。如果監(jiān)聽 127.0.0.1那么在服務(wù)器本機(jī)用curl能通但局域網(wǎng)其他機(jī)器永遠(yuǎn)打不開。這個(gè)問題出現(xiàn)頻率非常高我排查了很久才意識(shí)到是 Flask 的運(yùn)行參數(shù)問題。用 uWSGI 把 Flask 跑在 127.0.0.1:3031Nginx 再對(duì)外監(jiān)聽 80 端口相當(dāng)于把內(nèi)網(wǎng)服務(wù)和對(duì)外開放隔離開。Nginx 還順手做了靜態(tài)文件服務(wù)、連接管理、訪問日志這些單靠 Flask 開發(fā)服務(wù)器做不好。3.4 對(duì)外開放訪問與防火墻局域網(wǎng)內(nèi)訪問已經(jīng)通了但為了演示更完整的網(wǎng)絡(luò)權(quán)限控制我還在服務(wù)器上開了防火墻。Ubuntu 自帶的 ufw 操作比較簡(jiǎn)單sudo ufw allow 22/tcp # SSH 管理 sudo ufw allow 80/tcp # HTTP 訪問 sudo ufw allow 3306/tcp # 僅演示需要實(shí)際上不建議對(duì)外開放數(shù)據(jù)庫端口開放 3306 只是為了讓學(xué)生遠(yuǎn)程連接數(shù)據(jù)庫看表結(jié)構(gòu)真實(shí)環(huán)境必須關(guān)掉否則非常容易被掃描器爆破。我在安全日志里看到大量來自外網(wǎng)的 MySQL 連接嘗試才意識(shí)到數(shù)據(jù)庫端口暴露的嚴(yán)重性。后來取消了 3306 的外網(wǎng)放行只允許內(nèi)網(wǎng)網(wǎng)段訪問。這本身就是一次很好的“訪問控制”教學(xué)案例。4. 聯(lián)調(diào)測(cè)試與問題排查實(shí)錄4.1 常見問題速查表整個(gè)課設(shè)調(diào)試過程中我遇到過不少問題整理成一張速查表按照癥狀、原因、解法三列來寫癥狀可能原因解決辦法瀏覽器訪問 IP 顯示拒絕連接Nginx 未啟動(dòng)或監(jiān)聽端口不對(duì)systemctl status nginx檢查ss -tlnp局域網(wǎng)其他電腦打不開Flask 監(jiān)聽了 127.0.0.1uWSGI 綁定0.0.0.0或走 Nginx 反向代理頁面能開但 CSS/圖片加載失敗Nginx 配置沒包含location /static/補(bǔ)上靜態(tài)目錄映射重啟 Nginx視頻播放卡頓或無法拖進(jìn)度Nginx 沒開啟 Range 或文件路徑錯(cuò)誤在 location 中加入add_header Accept-Ranges bytes;留言板中文亂碼數(shù)據(jù)庫字符集不是 utf8mb4重建表指定DEFAULT CHARSETutf8mb4域名在別人電腦上解析不了只配了本機(jī) hosts用 dnsmasq 內(nèi)網(wǎng)DNS或改路由器DNS數(shù)據(jù)庫連接超時(shí)MySQL 綁定地址為 127.0.0.1修改bind-address 0.0.0.0授權(quán)允許遠(yuǎn)訪問訪問日志里出現(xiàn)大量重復(fù)請(qǐng)求可能是網(wǎng)頁輪詢或爬蟲用 Nginx 的limit_req模塊限制單IP請(qǐng)求頻率4.2 一次“異常流量”告警的排查手記調(diào)試接近尾聲時(shí)學(xué)校機(jī)房里的安全網(wǎng)關(guān)彈了一個(gè)提示“系統(tǒng)檢測(cè)到您的計(jì)算機(jī)網(wǎng)絡(luò)中存在異常流量?!边@是我遇到過最有意思的一個(gè)問題因?yàn)榫W(wǎng)站明明功能正常怎么會(huì)有異常流量。排查第一步我先看 Nginx 的訪問日志。發(fā)現(xiàn)某個(gè) IP 在幾十秒內(nèi)反復(fù)請(qǐng)求/admin/login.php、/wp-login.php、/.env這類路徑。這是一臺(tái)掃描器在遍歷網(wǎng)站試圖找后臺(tái)入口和配置漏洞并不是網(wǎng)站本身出問題。安全網(wǎng)關(guān)檢測(cè)到這種高頻探測(cè)就把它標(biāo)記為異常流量。進(jìn)一步用ss查看連接狀態(tài)發(fā)現(xiàn)來自那個(gè) IP 的 TCP 連接保持在 SYN_RECV 狀態(tài)說明它在不停嘗試建立新連接但在等第三次握手確認(rèn)典型的半連接掃描特征。我用 tcpdump 抓包確認(rèn)sudo tcpdump -i eth0 -n tcp port 80 and host 192.168.xx.xx抓到的包里全是 SYN 請(qǐng)求沒有后續(xù)正常的 HTTP GET這基本可以確認(rèn)是端口掃描或者惡意探測(cè)。解決辦法是在 Nginx 里限制并發(fā)和請(qǐng)求頻率limit_req_zone $binary_remote_addr zonecourse_limit:10m rate5r/s; server { listen 80; server_name course.jingpin.local; location / { limit_req zonecourse_limit burst10 nodelay; include uwsgi_params; uwsgi_pass 127.0.0.1:3031; } }同時(shí)在防火墻里只允許校園網(wǎng)網(wǎng)段訪問阻斷其他來源的探測(cè)。經(jīng)過處理后安全網(wǎng)關(guān)的告警逐漸消失。這個(gè)案例特別適合寫進(jìn)課設(shè)報(bào)告因?yàn)樗恰傲髁慨惓z測(cè)”和“訪問控制策略”的活教材比單純做網(wǎng)站模板要深刻得多。4.3 幾個(gè)非常值得注意的坑除了上面表格里的問題還有幾個(gè)隱蔽的坑。第一是 Nginx 的緩存我改了 CSS 文件后瀏覽器里始終是舊的清緩存也沒用。原因是有個(gè)反向代理層把靜態(tài)資源緩存了最后在 Nginx 的 location 里加proxy_cache_bypass或者給靜態(tài)文件請(qǐng)求加版本號(hào)參數(shù)才解決。第二是 MySQL 授權(quán)時(shí)不能只給rootlocalhost授權(quán)。要從 Flask 后端連數(shù)據(jù)庫用的用戶最好是單獨(dú)創(chuàng)建的例如course_user并只授權(quán)這個(gè)庫的權(quán)限CREATE USER course_userlocalhost IDENTIFIED BY your_password; GRANT ALL PRIVILEGES ON course.* TO course_userlocalhost; FLUSH PRIVILEGES;這樣可以避免應(yīng)用賬號(hào)直接使用 root 的高權(quán)限哪怕被注入了也刪不了其他庫。第三是上傳課件和視頻時(shí)文件名一定不要用中文和空格。早期我把文件名直接放到 URL 里瀏覽器會(huì)轉(zhuǎn)義鏈接反復(fù)失效。后來統(tǒng)一改成英文和下劃線再用數(shù)據(jù)庫記錄原始文件名展示時(shí)讀取原始文件名給用戶下載這樣既不破壞 URL也能正常顯示中文名稱。這個(gè)經(jīng)驗(yàn)在處理所有靜態(tài)資源時(shí)都通用。5. 驗(yàn)收演示與經(jīng)驗(yàn)擴(kuò)展5.1 演示時(shí)怎么講出“計(jì)算機(jī)網(wǎng)絡(luò)”含量答辯和驗(yàn)收的時(shí)候不要一上來就點(diǎn)開首頁而是先講網(wǎng)絡(luò)拓?fù)?。我?zhǔn)備了一張簡(jiǎn)單的拓?fù)鋱D一臺(tái) Web/數(shù)據(jù)庫服務(wù)器、一臺(tái)路由器/交換機(jī)、若干終端設(shè)備用文字標(biāo)注每臺(tái)設(shè)備的 IP、網(wǎng)關(guān)和 DNS。然后現(xiàn)場(chǎng)演示三件事第一在終端上用ping course.jingpin.local能看到域名解析成 192.168.10.10并且時(shí)延正常。第二打開 Wireshark在服務(wù)器端抓訪問課程首頁的包能看到 TCP 三次握手和 HTTP GET 請(qǐng)求。第三在留言板提交一條留言再到數(shù)據(jù)庫里查這條記錄證明前后端和數(shù)據(jù)庫鏈路是通的。這三步操作比講十頁 PPT 都有說服力老師一看就知道你確實(shí)理解了網(wǎng)絡(luò)通信的完整路徑。5.2 報(bào)告和收尾建議課設(shè)報(bào)告的結(jié)構(gòu)我建議分這幾塊需求分析、總體設(shè)計(jì)、網(wǎng)絡(luò)拓?fù)渑c IP 規(guī)劃、數(shù)據(jù)庫設(shè)計(jì)、核心功能實(shí)現(xiàn)、測(cè)試結(jié)果、故障處理記錄、總結(jié)展望。其中“故障處理記錄”一定要寫實(shí)比如我前面寫的異常流量告警就詳細(xì)寫了觀測(cè)現(xiàn)象、抓包結(jié)果、處理方案和最終效果。老師最反感那種全篇都是“實(shí)現(xiàn)了什么功能”但沒有任何問題分析的報(bào)告因?yàn)檎鎸?shí)項(xiàng)目不可能沒有坑。報(bào)告里的 IP 地址表、域名映射、Nginx 配置片段、數(shù)據(jù)庫表結(jié)構(gòu)全部要有注釋。我還在附錄里放了 Wireshark 抓包截圖每張圖下配兩三句說明解釋這個(gè)包是在哪個(gè)階段出現(xiàn)、標(biāo)志位有什么含義、對(duì)應(yīng)哪一次通信過程。這樣做的好處是即使答辯時(shí)間很短老師翻到附錄也能快速理解你的網(wǎng)絡(luò)設(shè)計(jì)。5.3 如果再讓我做一次我會(huì)改什么這個(gè)項(xiàng)目做完之后我最大的體會(huì)是精品課程網(wǎng)站設(shè)計(jì)的難點(diǎn)不在頁面而在“讓這個(gè)網(wǎng)站在正確的位置提供正確的服務(wù)”。如果再給我一次機(jī)會(huì)我會(huì)直接給網(wǎng)站加上 HTTPS用自簽名證書雖然會(huì)被瀏覽器報(bào)不安全但能借機(jī)把 SSL/TLS 握手過程講明白也算多一個(gè)知識(shí)亮點(diǎn)。我也會(huì)把部署過程寫成自動(dòng)化腳本用 Ansible 一鍵配置 Nginx、MySQL 和 Flask 環(huán)境這樣換一個(gè)網(wǎng)絡(luò)環(huán)境重新部署時(shí)就不用一個(gè)命令一個(gè)命令地敲。對(duì)于還在做課設(shè)的人我最后分享一個(gè)實(shí)用技巧每一步配置完成之后立刻用命令驗(yàn)證。比如改完 Nginx 配置就運(yùn)行nginx -t改完 hosts 就ping一下域名改完數(shù)據(jù)庫授權(quán)就用遠(yuǎn)程客戶端連一次。別等到所有配置都寫完了再一次性測(cè)試否則一旦報(bào)錯(cuò)你會(huì)分不清是 Web 服務(wù)、數(shù)據(jù)庫、防火墻還是域名解析出問題。小步驗(yàn)證才是這種網(wǎng)絡(luò)類課設(shè)最省時(shí)間的推進(jìn)方式。本文還有配套的精品資源點(diǎn)擊獲取