Python網路程式設計(基礎總結入門經典)
Linux下檔案型別:
bcd -lsp
b(塊、裝置檔案)
c(字元裝置檔案)
d(目錄)
-(普通檔案)
l(連結檔案)
s(套接字檔案)
p(管道檔案)
kill -sig pid:通過pid傳送訊號殺死指定程式
kill -l:檢視作業系統內所所有sig訊號
ps -aux —> STAT表示程式狀態
訊號:
SIGHUP 斷開連結
SIGINT Ctrl + c
SIGQUIT Ctrl +
SIGTSTP Ctrl + z
SIGKILL 終止程式且不能被處理
SIGSTOP 暫停程式且不能被處理
SIGALRM 時鐘訊號
SIGCHLD 子程式改變狀態時父程式會收到此訊號
OSI七層模型 —–> 網路通訊的標準化流程
應用層: 提供使用者服務,具體的內容由特定的程式規定
表示層: 提供資料的加密和壓縮優化
會話層: 確定建立應用連結,選擇傳輸服務
傳輸層: 提供資料傳輸服務,進行流量控制
網路層: 路由選著,網路互聯
鏈路層: 提供鏈路交換,具體訊息的傳送
物理層: 物理硬體,介面,網路卡的規定
網路協議:
應用層:TFTP(檔案傳輸)、HTTP(超文字傳輸協議)、DNS(域名解析)、SMTP(郵件傳輸)
傳輸層:TCP、UDP
網路層:IP
物理層:IEEE
IP地址
本地使用:127.0.0.1 或 “localhost”
網路地址:“0.0.0.0” 或 “172.168.40.53”
IPv4: 點分十進位制 例如:192.168.1.3 取值0~255(32位)
IPv6: 128位
socket模組:
ifconfig:檢視本機IP (ens33:本地IP lo:本地回還)
ipconfig:windoes中
socket.gethostname() : 獲取本機主機名
socket.gethostbyname(`tedu`) : 利用主機名獲取ip
socket.gethostbyname(`localhost`): 獲取本地ip
socket.gethostbyaddr(`127.0.0.1`) 訪問主機IP地址
socket.inet_aton(`192.168.1.2`) IP十六進位制轉換
socket.inet_ntoa(b`xc0xa8x01 2`) IP十進位制轉換
socket.getservbyname(`ssh`) 獲取應用程式的埠
建立TCP服務端套接字:
sockfd.socket(sock_family = AF_INET,
sock_tpye = SOCK_STREAM,
proto = 0)
sockfd.bind(addr) 繫結地址
sockfd.listen(n) 設定監聽套接字
connfd,addr = sockfd.accept() 等待接受客戶端連結
data = connfd.recv(buffersize) 接收訊息
connfd.send(data) 傳送訊息
sockfd.close() 關閉套接字
建立TCP客戶端套接字:
sockfd.socket(sock_family = AF_INET,
sock_tpye = SOCK_STREAM,
proto = 0)
sockfd.bind(addr) 繫結地址
sockfd.connect(addr) 連結服務端
data = connfd.recv(buffersize) 接收訊息
connfd.send(data) 傳送訊息
sockfd.close() 關閉套接字
建立UDP客戶端套接字:
sockfd.socket(sock_family = AF_INET,
sock_tpye = SOCK_DGRAM,
proto = 0)
sockfd.bind(addr) 繫結地址
data = sockfd.recvfrom(buffersize) 接收訊息
sockfd.sendto(data, addr) 傳送訊息
sockfd.close() 關閉套接字
建立UDP客戶端套接字:
sockfd.socket(sock_family = AF_INET,
sock_tpye = SOCK_DGRAM,
proto = 0)
data = sockfd.recvfrom(buffersize) 接收訊息
sockfd.sendto(data, addr) 傳送訊息
sockfd.close() 關閉套接字
建立本地套接字服務端:
sockfd = socket(AF_UNIX, SOCK_STREAM) 建立本地套接字物件
sockfd.bind(file) 繫結套接字檔案
sockfd.listen(3) 監聽
connfd,addr = sockfd.accept() 等待連結
connfd.recv(buffersize) 接收訊息
connfd.send(data) 傳送訊息
sockfd.close() 關閉套接字
建立本地套接字客戶端:
sockfd = socket(AF_UNIX, SOCK_STREAM) 建立本地套接字物件
sockfd.connect(sock_file) 連結服務端
connfd.recv(buffersize) 接收訊息
connfd.send(data) 傳送訊息
sockfd.close() 關閉套接字
套接字屬性:
sockfd.type 返回套接字型別
sockfd.family 返回地址型別
套接字方法:
sockfd.fileno() 獲取套接字的檔案描述符
sockfd.getsockname() 獲取套結字繫結的地址
sockfd.getpeername() 獲取連結套接字客戶端的地址
sockfd.setsockopt(level,optname, value) 設定埠可立即重用
sockfd.setblocking(False) 將套接字設定為非阻塞狀態
sockfd.settimeout(sec) 設定套接字的超時時間
select模組: IO多路複用,阻塞等待監控的IO事件發生
rs, ws, xs = select(rlist, 等待處理的IO
wlist 想要主動處理的IO
xlist[, 出錯希望去處理的IO
timeout]) 超時檢測
p = select.poll 建立poll物件
p.register(s, POLLIN | PLLERR) 註冊關注的IO
events = p.poll() 監控關注的IO事件
multiprocessing模組: 建立程式物件
Process(target, 要繫結的函式
name, 給程式起的名稱
args, 元組給target函式位置傳參
kwargs) 字典給target函式鍵值傳參
p.start() 啟動程式terget繫結函式
p.join([timeout]) 阻塞等待子程式退出
p.name 獲取程式名(屬性)
p.daemon 設定為True主程式結束殺死所有子程式(必須start()前設定)
p.is_alive() 判斷程式是處於alive狀態(存活)
p.pid 獲取建立程式的pid號(屬性)
pool = pool(x) 建立程式池物件(程式池大小)
pool.apply_async(fun, 要執行的函式(非同步執行)
args, 以元組形式為fun傳參
kwds) 以字典形式為fun傳參
pool.apply(fun, args, kwds) (同步執行)
r = pool.map(fun,range(6)) 將要執行的事件放入程式池
pool.close() 關閉程式池
pool.join() 回收程式池
fd1,fd2 = Pipe(duplex=True) 建立管道(Flase:fd1只讀,fd2只寫)
fd.recv() 從管道讀取資訊空則阻塞
fd.send(data) 向管道寫入內容滿則阻塞
q = Queue(maxsize=0) 建立佇列物件(存放多少條訊息)
q.put(data, 存入訊息(支援Python資料型別)
[block, 預設阻塞 False:非阻塞
timeout]) block為True是表示超時檢測
data = q.get([block,timeout]) 取出訊息
q.full() 判斷佇列是否為滿
q.empty() 判斷佇列是否為空
q.qsize() 獲取佇列中訊息的數量
q.close() 關閉佇列
shm = Value(ctype, 建立共享記憶體共享空間
obj) ctype字串:(C語言資料型別),obj初始資料
shm.value 表示共享記憶體的值(可以賦值)
shm = Array(ctype,obj) 建立共享記憶體共享空間
sem = Semaphore(num) 建立訊號量
sem.acquire() 將訊號量減1 0時阻塞
sem.release() 將訊號量加1
sem.get_value() 獲取當前訊號量的值(數量)
e = Event() 建立Event事件物件
e.wait([timeout]) 阻塞程式 直到事件物件被set
e.set.() 讓事件物件變為被設定狀態
e.clear() 使事件物件清除設定狀態
e.is_set() 判斷當前事件是否被set
Lock = Lock() 建立鎖物件
lock.acquire() 上鎖
lock.release() 解鎖
threading 模組: 建立執行緒物件
threshold.Thread(target, 執行緒函式
name, 執行緒名字
args, 元組給執行緒函式位置傳參
kwargs) 字典給執行緒函式位置傳參
t.start() 啟動執行緒
t.join() 回收執行緒
t.name 執行緒名
t.daemon = True 主執行緒退出分支執行緒也退出
t.setDaemon(True) 主執行緒退出分支執行緒也退出
t.isDaemon 檢視daemon值
t.setName(“name”) 設定執行緒名稱
t.is_alive() 檢視執行緒狀態
threading.currentThread() 獲取當前程式物件
e = threading.Event() 建立Event事件物件
e.wait([timeout]) 事件阻塞
e.set() 設定事件
e.clear() 清除事件
lock = threading.Lock() 建立鎖物件
lock.acquire() 上鎖
lock.release() 解鎖
socketserver整合併發模組:
StreamRequestHandler 處理tcp請求
DatagramRequestHandler 處理udp請求
ForkingMixIn 建立多程式
ThreadingMixIn 建立多執行緒
TCPServer 建立tcp server
UDPServer 建立udp server
ForkingTCPServer ForkingMixIn + TCPServer
ForkingUDPServer ForkingMixIn + UDPServer
ThreadingTCPServer ThreadingMixIn + TCPServer
ThreadingUDPServer ThreadingMixIn + UDPServer
signal模組:
signal.alarm(sec) 設定時鐘訊號給自己SIGALRM訊號
signal.pause() 阻塞程式,等待一個訊號
signal.signal(sig, 要處理的訊號
handler) 處理方法(SIG_DFL:預設 SIG_IGN:忽略 func:自定義函式)
sys模組補充:
sys.argv 獲取從命令列獲取的引數內容列表
sys.stdin 0 標準輸入IO檔案描述符
sys.stdout 1 標準輸出IO檔案描述符
sys.stderr 2 錯誤IO檔案描述符
sys.exit([status]) 退出一個程式(狀態:退出提示字串)
字串方法補充:
S.splitlines 按行分隔
os模組補充:
os.path.exists(file) 判斷一個檔案是否存在
os.remove(file) 刪除檔案
os.unlink(file) 刪除檔案
pid = os.fork() 建立程式 失敗-1 成功0
os.getpid() 獲取程式的PID號
os.getppid() 獲取父程式的PID
os.exit(status) 退出一個程式(狀態:整數 預設0)
pid,status = os.wait() 塞等待處理子程式的退出
os.WEXITSTATUS(status) 獲取原來退出狀態
pid,status = os.waitpid(pid,option) 阻塞等待處理子程式的退出
os.path.getsize(`./1.txt`) 讀取檔案的大小
os.kill(pid,sig) 傳送一個訊號給某個程式
os.listdir(path) 獲取指定目錄檔案列表
os.path.isfile() 判斷一個 檔案是否為普通檔案
os.path.isdir() 判斷一個檔案是否為目錄
傳輸層服務:
面向連線的傳輸服務(tcp協議):
傳輸特徵:
可靠的資料傳輸:
可靠性:無失序、無差錯、無重複、無丟失、無重複
在資料傳輸前和傳輸後需要建立連線和斷開連結
面向傳輸服務建立連線的過程:‘三次握手’
1.客戶端向伺服器傳送連結請求
2.伺服器接受到請求進行確認,返回確認報文
3.客戶端收到伺服器回覆最終確認連結
面向傳輸服務斷開連結的過程:‘四次揮手’
1.主動方傳送報文,告知被動方要斷開連結
2.被動方回覆報文,表示已經接受到請求,準備斷開
3.被動方再次傳送報文,表示準備處理就緒,可以斷開
4.主動方傳送確認報文,斷開連結
應用情況:
適用於傳輸較大的內容或檔案,網路良好,
需要保證傳輸可靠性的情況
e.g. 資訊聊天,檔案上傳下載,郵件,網頁獲取
面向無連線的傳輸服務(udp協議):
不保證傳輸的可靠性
沒有建立連線和斷開的過程
資料的收發比較自由
適用情況:
網路情況較差,對可靠性要求不高,收發訊息的兩端
e.g.:網路視訊,群聊,廣播等
收發函式特性:
recv特徵:
如果建立的另一端連結被斷開, 則recv立即返回空字串
recv是從接受緩衝區取出內容,當緩衝區為空則阻塞
recv如果一次接受不完緩衝區的內容,下次執行會自動接受
send特徵:
如果傳送的另一端不存在則會產生pipe…異常
send是從傳送緩衝區傳送內容當緩衝區為滿則堵塞
http協議:
超文字傳輸協議
用途:
網站中瀏覽區器網頁的獲取,基於網站事物資料傳輸
編寫基於http協議的資料傳輸
特點:
1.應用層協議,傳輸層使用tcp服務
2.簡單、靈活,可以使用多種程式語言操作
3.無狀態的協議,既不用記錄使用者的輸入內容
4.http1.1 —> http2.0(還沒釋出) 技術的成熟和穩定性
http請求(request):
1.請求格式:
1)請求行:說明具體的請求類別和內容
GET /index.html /HTTP/1.1
請求類別 請求內容 協議版本
2)請求類別:
GET:獲取網路資源
POST:提交一定的附加資料
HEAD:獲取相應頭
PUT:更新伺服器資源
DELETE:刪除伺服器資源
CONNECT:未使用
TRACE:用於測試
OPTIONS:獲取伺服器效能資訊
2.請求頭:對請求的具體描述
Accept:text/html
每一個鍵值對佔一行,描述了一個特定資訊
3.空行
4.請求體:具體的引數或提交的內容
get引數或者post提交的內容
http響應(response):
1.響應格式:
1)響應行:反饋具體的響應情況
HTTP/1.1 20 OK
版本協議 響應碼 附加資訊
3)響應碼:
1xx:提示資訊,表示請求已經接收
2xx:響應成功
3xx:響應需要定向
4xx:客戶端錯誤
5xx:伺服器端錯誤
3)常見響應碼:
200 成功
404 請求內容不存在
401 沒有訪問許可權
500 伺服器未知錯誤
503 伺服器暫時無法執行
2.響應頭:對響應內容的具體描述
3.空行
4.響應體:
將客戶端請求內容進行返回
IO多路複用
定義:
通過一個監測,可以同時監控多個IO事件的行為,
當那個IO可以執行,讓這個IO事件發生
同時監控多個IO事件,當哪個IO事件準備就緒就執行哪個IO事件
此時形成多個IO時間都可以操作的現象,不必逐個等待執行
IO準備就緒:
IO事件即將發生時的臨界狀態是不可逆轉的
在程式中存在的IO事件中選擇要監測的事件
建立監測,將監測的IO事件註冊
等待監測的IO事件發生,判斷是什麼事件
處理相應的IO
poll方法實現IO多路複用:
1.建立poll物件:
p = select.poll
2.註冊關注的IO:
p.register(s, POLLIN | PLLERR)
不關注:
p.unregister(s)
事件類別:
POLLIN POLLOUT POLLERR POLLHUP POLLPRI
rlist wlist xlist 斷開 緊急處理
3.監控IO:
events = p.poll()
功能:監控關注的IO事件
返回值:
返回發生IO事件
events是一個列表[(fileno, evnet), (), ()….]
每個就緒IO對應一個元組(描述符,就緒事件)
IO地圖:{s.fileno():s}
4.處理IO事件
位運算:
按照二進位制位進行位運算操作
& 按為與 |按位或 ^按位異或
<< 左異 >>右移
11 1011
14 1110
& 1010 有0得0
| 1111 有1得1
^ 0101 相同為0不同為1
11 << 2 == 44 右側補零(乘2乘2次)
14 >> 2 == 3 擠掉右側的數字(地板除2除2次)
使用:
1.在低層硬體時操作暫存器
2.做標誌位的過濾
多工程式設計:
意義:
充分利用計算機資源,同時執行多個任務,
提高程式整體的執行效率
定義:
通過程式利用計算機的多個核心達到同時執行多個任務的目的
因此達到提升程式執行效率的目的
實施方案:
多程式程式設計
多執行緒程式設計
並行:
多個計算機核心在同時處理多個任務,
這時多個任務之間是並行關係
併發:
同時執行多個任務,核心在多個任務之間的不斷切換,
達到多個任務都會執行的處理效果
此時多個任務之間的併發關係
程式:
是一個可執行檔案,是靜態的,只佔有磁碟
不佔用計算機執行資源
程式:
程式在計算機中的一次執行過程
是一個動態過程,佔有一定的計算機資源
有一定的生命週期
注:
同一個程式不同的執行過程是不同的程式,
因為分配的資源和生命週期都不同
程式的建立過程:
1.使用者啟動一個程式,或是呼叫介面發起程式建立
2.作業系統接收使用者請求分配計算機資源建立程式
3.作業系統將一定狀態的程式提供給使用者使用
4.使用者利用操作提供的程式完成任務
CPU時間片:
如果有個程式佔有CPU此時我們稱為該程式佔有CPU的時間片
多個程式任務或輪流佔有CPU時間片並形成併發效果
程式資訊(process)
PCB(程式控制塊):
程式建立後 會自動在記憶體中產生一個空間存放程式資訊
程式資訊:
程式ID 程式佔有記憶體的位置 建立時間、建立位置
檢視系統程式資訊:ps -aux
PID(process ID):
在作業系統中每個程式都有唯一的PID值是由系統分配的
程式特徵:
程式是作業系統分配資源的最小單元
每個程式擁有自己獨立的執行空間(4個G的虛擬記憶體空間)
程式之間相互獨立各不影響
程式的狀態:
三態:
就緒狀態:
程式具備執行條件,等待系統分配處理器資源進入執行態
執行態:
程式佔有CPU處於執行狀態
等待態:
程式暫時不具備執行條件,需要阻塞等待
五態:
在三態的基礎上增加新建和終止態
新建:
建立一個新的程式,獲取系統資源的過程
終止:
程式執行結束,釋放資源的過程
ps -aux —> STAT表示程式狀態:
D 等待態 阻塞 不可中斷等待態
S 等待態 睡眠 可中斷等待態
T 等待態 暫停 暫停執行
R 執行態(就緒態)
Z 殭屍
+ 前臺程式(在終端執行)
< 有較高優先順序的程式
N 較低優先順序的程式
s 回話組
l 有程式連結
程式的優先順序:
top 檢視程式執行態優先順序
取值範圍:-20~19 -20最高
nice:
以指定的優先順序執行一個程式
nice -9 ./hello.py 以9的優先順序執行
sudo nice –9 ./hello.py 以-9優先順序執行
首行新增 #! /usr/bin/python3 指定執行器
執行:./hello.py
修改程式許可權新增可執行許可權
chmod 775 hello.py
孤兒程式 :
當父程式先於子程式退出,此時子程式就會成為孤兒程式。
* 孤兒程式會被系統指定程式收養,即系統程式會成為孤兒
程式新的父程式。系統程式會自動處理孤兒程式退出狀態
殭屍程式 :
子程式先於父程式退出,父程式沒有處理子程式的退出狀態,此時子程式就會成為殭屍程式
* 殭屍程式會滯留部分PCB資訊在記憶體中,大量的殭屍進
程會消耗系統的記憶體資源,所以要儘量避免殭屍程式產生
如何避免殭屍程式產生?
* 父程式先退出
* 父程式處理子程式退出狀態
* 建立二級子程式
程式池技術:
產生原因:
如果有大量的任務需要多程式完成,而呼叫週期比較短且需要頻繁建立
此時可能產生大量程式頻繁建立銷燬的情況 消耗計算機資源較大
使用方法:
1.建立程式池,在池內放入適當數量的程式
2.將事件封裝成函式。放入到程式池
3.事件不斷執行,直到所有放入程式池事件執行完成
4.關閉程式池,回收程式
同步互斥機制
目的:
解決對共有資源產生的資源爭奪
臨界資源:
多個程式或執行緒都可以操作的資源
臨界區:
操作臨界資源的程式碼段
同步:
同步是一種合作關係,為完成某個任務,
多程式或者多個執行緒之間形成的一種協調
按照約定執行,相互告知,共同完成任務
互斥:
互斥是一種制約關係,當一個程式或者執行緒
進入臨界區操作資源時採用上鎖的方式,
阻止其他程式操作,直到解鎖後才能讓出資源
多執行緒:
什麼是執行緒(thread)?
執行緒也是一種多工程式設計方式,可以使用計算機的多核資源
執行緒被稱為輕量級的程式
執行緒的特徵:
1.一個程式可以包含多個執行緒
2.執行緒是計算機核心使用的最小單位
3.執行緒也是一個執行過程,也要消耗計算機資源
4.多個執行緒共享共用程式的資源
5.執行緒也有自己的特徵屬性,TID、指令集、執行緒棧
6.多個執行緒之間獨立執行互不干擾 空間不獨立(都消耗程式空間)
7.執行緒的建立刪除消耗的資源要小於程式 執行緒/程式(1/20)
執行緒通訊:
多個執行緒共用執行緒空間,所以程式的全域性變數對程式內執行緒均可見
執行緒的通訊方法就是使用去全域性變數通訊
注:
執行緒間使用全域性變數程式通訊時,全域性變數為共享資源
往往需要同步互斥機制
程式和執行緒的區別和聯絡:
1.兩者都是多工程式設計的方式 都能夠使用計算機的多核
2.程式的建立和刪除要比執行緒消耗更多的計算機資源
3.程式空間獨立,資料安全性好,有專門的程式間的通訊方法
4.執行緒使用全域性變數,更加簡單,但需要同步互斥操作
5.一個程式可以包含多個執行緒,執行緒共享程式空間資源
6.程式執行緒都獨立執行,有自己的特有屬性
使用情況:
1.一個程式中併發任務比較多,比較簡單,適合使用多執行緒
2.如果資料程式比較複雜,特別是可能多個任務通訊比較多的時候
要考慮使用執行緒同步互斥的複雜性
3.多個任務存在明顯差異,和功能分離的時候沒有必要一定寫入到一個程式中
4.使用Python要考慮到GIL的問題
Pyhthon執行緒GIL問題:
GIL (全域性直譯器鎖)
Python —>支援執行緒操作—>出現IO同步互斥—>加鎖—>超級鎖,給直譯器加鎖
後果:
同一時刻一個直譯器只解釋一個執行緒
此時其他執行緒需要等待。大大降低了Python執行緒的執行效率
只能實現併發不能實現並行
Python GIL問題解決方案:
1.修改c直譯器
2.儘量使用多程式進行並行操作
3.Python執行緒儘量用在高延遲多阻塞的IO情形
3.不使用CPython 使用C#、JAVA 做的得直譯器
網路伺服器基礎:
迴圈伺服器::
單程式程式,迴圈接受客戶請求,處理請求,處理完畢後再接受下一次請求
特點:
每次只能處理一個客戶端請求,如果客戶端長期佔有伺服器則無法處理其他客戶端
請求
優點:
實現簡單,佔用資源少
缺點:
無法同時處理多個客戶端,體驗差
使用情況:
任務短暫,可以快速完成,udp比tcp更適合迴圈
併發伺服器:
能夠同時處理多個客戶端任務請求
IO併發:
IO多路複用 協程
優點:
可以實現IO併發操作,佔用系統資源少
缺點:
不能夠監控CPU密集的情況,並不能有長期阻塞
多程式/執行緒併發:
為每個客戶端單獨提供一個程式或執行緒,處理客戶端請求
優點:
客戶端可以長期佔有伺服器
缺點:
消耗計算機資源比較多
相關文章
- Python程式設計入門——基礎語法詳解(經典)Python程式設計
- 【Python入門基礎】網路程式設計Python程式設計
- Python基礎入門(6)- 物件導向程式設計Python物件程式設計
- Python程式設計入門基礎語法詳解Python程式設計
- JavaScript函數語言程式設計入門經典JavaScript函數程式設計
- [Python人工智慧] 一.神經網路入門及theano基礎程式碼講解Python人工智慧神經網路
- 【總結】10大Python庫介紹!Python基礎入門Python
- Java入門之基礎程式設計Java程式設計
- 好程式設計師Python培訓分享基礎入門Django程式設計師PythonDjango
- BootStrap基礎入門概述總結boot
- 好程式設計師Python培訓分享Python入門基礎知識程式設計師Python
- Linux-shell程式設計入門基礎Linux程式設計
- Java程式設計基礎29——JavaSE總結Java程式設計
- Python入門經典案例一Python
- Python 程式設計中常用的 12 種基礎知識總結Python程式設計
- Python 程式設計中常用的12種基礎知識總結Python程式設計
- C#程式設計基礎入門教程pdfC#程式設計
- Python程式設計入門Python程式設計
- python程式設計基礎Python程式設計
- Android程式設計基礎 • 【第1章 Android程式入門】Android程式設計
- 程式碼審計入門總結
- 【Python】基礎總結Python
- Python入門教程100天:Day08-物件導向程式設計基礎Python物件程式設計
- 《Python程式設計:從入門到實踐》 筆記(一)基礎知識Python程式設計筆記
- 零基礎入門Python的路徑Python
- python 程式設計基礎案例Python程式設計
- 計算機基礎與程式設計第十週總結計算機程式設計
- 必備電子技術經典資料彙總:基礎入門篇1.6G
- 程式設計和網路程式設計入門程式設計
- 從萌新到大神必讀書籍 《Python快樂程式設計基礎入門》Python程式設計
- 網路程式設計基礎程式設計
- C++入門經典第一章程式設計專案C++程式設計
- 【Python入門基礎】程式和執行緒Python執行緒
- Python入門基礎—購物車小程式Python
- Python入門基礎(8)Python
- Python 非同步程式設計入門Python非同步程式設計
- csharp入門經典CSharp
- 經典 backbone 總結