python socket編程---從使用Python開發一個Socket示例說到開發者的思維和習慣問題

今天主要說的是一個開發者的思維和習慣問題。

思維包括編程的思維和解決一個具體問題的分析思維,分析思路,分析方法,甚至是分析工具。

無論是好習慣還是不好的習慣,都是在者一天一天的思維中形成的。那些不好的習慣,久了確實不好改。所以說,如果今天你認識到了,那麼就從今天開始改,早改早受益,晚改痛苦一生。

先說一下今天的引子,那就是使用Python開發一個簡單的Socket應用,就是一個client/server通信的小例子。

假設現在需要我們使用python開發一個socket的聊天應用,可能會遇到下面的問題。

  • python沒有用過,怎麼辦呢?
  • 我用過python,可是我們開發過socket方面的應用?
  • 我還不知道socket是什麼東西呢?
  • socket大概我記得,套接字嗎,ip+port,具體的tcp和udp我不不太清楚。

其實我們幾乎每天都可能會解決一些我們沒有解決過的問題,有可能是沒有用過的類庫,沒有聽過的技術,沒有用過的語言,甚至是沒有聽過的概念。

其實,這些都不是問題。只要你有一個較好的思維習慣,較好的思維方式,較好的解決問題的方法,那你就什麼都不用怕了。

大家可以仔細的看看和研究一下,其實這10年20年,沒有出現任何新的技術,出現的都是新的概念,所謂的新技術都是對老技術的挖掘,重新組合,應用到新的領域,用新的視角解決新的問題,其實用到的根本還是那些技術的技術知識。

這些技術知識包括:

  1. 語言的語法,語言的基本結構(順序,選擇,循環)。
  2. 技術的基礎理論,例如,數據庫理論,文件系統理論,今天我們演示用的socket通信理論。

當然了,除了上面的硬技術,你還需要一些軟技術。例如,思考方法,好的習慣,好的工具,好的溝通,好的理解力,好的領悟力。

現在出現的東西都是上面這些東西的組合,或者將這些組合解決了新出現的問題,又或者是變了一種思路來解決老問題,等等諸如此類的組合。

舉個例子來說吧。“雲計算”,很火吧,各種語言的雲計算,各種框架的雲計算,但是如果你陷入這些語言和框架,結果可想而知,精力被耗盡,但是不見得真正理解多少,甚至是框架都會不完,因爲太多了。

這就需要我們加強理論基礎知識,雲的理論基礎就是分佈式,分佈式出來很多年了吧。好了,先學習和理解分佈式,理解雲就迎刃而解了。分佈式+調度+服務器集羣+通信=雲,你看看,哪個是新的,哪個是以前沒有的,對不對呢!

 

就拿socket舉例子吧。只舉個小例子,就是分別用tcp和udp實現聊天。

我們先不要google找python socket代碼。我們先回憶一下我們學過的socket通信部分,或者說先找一本socket通信的書或者文章,看看通信的原理和過程。當然,不是要你通篇看完,通篇理解,完全弄懂。tcp和udp裏面的細節你可能不知道,沒有關係,如果需要的話,後面再來看。但至少你可以使用僞代碼描述tcp和udp的通信流程,或者在紙上可以畫出通信流程,使用流程圖描述你要實現的功能。

別小看僞代碼和流程圖這兩個簡單的東西,它代表了你的思考過程,你的思維方法,和你選擇的思維工具,是良好習慣的開端,一定要堅持,直到這些都成爲你的習慣。

有了這些東西,別人會對你高看一眼的,會覺得你比較靠譜,就會給你更有挑戰的工作,給你表現的機會,那麼你就。。。。。。。。。。。。。。大家都明白的。你的各種想法都有機會實現了,否則就都是空白。

 

圖1 tcp通信圖

 

上圖是一張socket的tcp通信簡圖,我們都知道tcp的通信需要三次握手。tcp是可靠的、面向連接的、盡力傳輸的協議,而udp是不可靠的、面向非連接的、不盡力傳輸的協議。但是不可靠不代表它沒有用,udp有自己的應用場景,語音和視頻幾乎都在使用udp協議,它的不可靠只是相對於tcp來說的,但是它的好處就是效率,高效在某些場景要比可靠性重要。這就涉及trade-off了,也就是權衡,需要根據你的應用權衡利弊,然後進行選擇。

在socket選擇初始化一個tcp協議的socket之後,就會綁定一個地址和端口,然後開始listen,客戶端連接這個listen的tcp之後,服務端會accept這個請求,然後產生一個新的socket,雙方使用這個新的socket(地址和端口,地址還是上面listen的地址,端口會是一個新的,這個從打印出的結果中可以看出)進行後續的通信。原來的端口會繼續的listen新的請求。

 

下面是tcpServer的代碼

 

  1. import socket 
  2.  
  3. HOST='192.168.0.37' 
  4. PORT=50000 
  5. BUFFER=4096 
  6. sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
  7. sock.bind((HOST,PORT)) 
  8. sock.listen(0
  9. print('tcpServer listen at: %s:%s\n\r' %(HOST,PORT)) 
  10. while True
  11.   client_sock,client_addr=sock.accept() 
  12.   print('%s:%s connect' %client_addr) 
  13.   while True
  14.     recv=client_sock.recv(BUFFER
  15.     if not recv: 
  16.       client_sock.close() 
  17.       break 
  18.     print('[Client %s:%s said]:%s' % (client_addr[0],client_addr[1],recv)) 
  19.     client_sock.send('tcpServer has received your message'
  20. sock.close() 

socket.SOCK_STREAM是用來指定socket是基於tcp協議的。

下面是對應的客戶端代碼

 

  1. import socket 
  2.  
  3. HOST='192.168.0.37' 
  4. PORT=50000
  5. BUFFER=4096 
  6.  
  7. sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
  8. sock.connect((HOST,PORT)) 
  9. sock.send('hello, tcpServer!'
  10. recv=sock.recv(BUFFER) 
  11. print('[tcpServer said]: %s' % recv) 
  12. sock.close() 

 

下面是udpServer的代碼

 

  1. import socket 
  2.  
  3. HOST='192.168.0.37' 
  4. PORT=50001
  5. BUFFER=4096 
  6. sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 
  7. sock.bind((HOST,PORT)) 
  8. #sock.listen(0) 
  9. print('tcpServer listen at: %s:%s\n\r' %(HOST,PORT)) 
  10. while True
  11.   #client_sock,client_addr=sock.accept() 
  12.   #print('%s:%s connect' %client_addr) 
  13.   while True
  14.     recv,client_addr=sock.recvfrom(BUFFER) 
  15.     if not recv: 
  16.        
  17.       break 
  18.     print('[Client %s:%s said]:%s' % (client_addr[0],client_addr[1],recv)) 
  19.     sock.sendto('tcpServer has received your message',client_addr) 
  20. sock.close() 

你會發現由於udp是非連接的,不需要三次握手,所以不需要進行listen,也不需要accept,直接通信就可以了。還有就是初始化socket的時候,通過指定

  1. socket.SOCK_DGRAM 

來實現初始化的socket是基於udp協議的。

如果初始化的是udp協議的socket,就不需要listen,也不存在accept,雙方通信的同時指明對方的地址和端口就可以了。

對應的客戶端代碼:

 

  1. #!/usr/bin/env python 
  2. # -*- coding: UTF-8 -*- 
  3.  
  4. import socket 
  5.  
  6. HOST='192.168.0.37' 
  7. PORT=50001 
  8. BUFFER=4096 
  9.  
  10. sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 
  11. sock.connect((HOST,PORT)) 
  12. sock.send('hello, tcpServer!'
  13. recv=sock.recv(BUFFER) 
  14. print('[tcpServer said]: %s' % recv) 
  15. sock.close() 
  16.  

 

說了上面這麼多,我的主要意思就是。開發者要加強理論基礎的學習,不要窮追猛打那些語言和框架,至少在窮追猛打的過程中,分出更多的精力關注基礎知識,基礎牢靠,上層建築才穩固且長久。

對於少數人,這已經形成他們的習慣了,他們已經及早的認識到了這個問題,這麼多年都是這麼做的。

對於大多數開發者來說,都是遇到問題,找語法,找例子,拔過來,改一改,debug,看效果,再debug,再看效果。問題可能解決了,但是過程是痛苦至極,年前的時候還不覺得如何,時間一長,發現開發原來是這麼的沒有意思,這麼的枯燥,每天都是這個過程,沒有新意,這麼多語言框架,什麼時候才能學完呢,感覺自己被拉着走,甚至是拖着走,沒有解脫的一天,除非dead。

不過也沒有關係,大多數人都是這麼過來的,那些牛人也是這麼過來的,只是他們很早就意識到了這個問題,然後及早的修正,及早的進入一條快車道。就像我一直說的,開發者的幾個階段是不能越過的,但是你可以比別人多花時間和精力,縮短這些必經階段的時間,這個很重要的。

如果你今天認識到了,那麼不要拖到明天,不要拖到下個項目,不要拖到下一個模塊,從現在開始,從這個項目開始,從這個模塊開始,修正自己,後面的路就會舒服很多。我不能保證後面你會如何如何,但是敢保證你會越來越舒服,就算是一直coding到退休,也不是在痛苦中coding,而是舒舒服服的coding。沒有人會對我們說“你30歲了,還在coding。。。。。。”,因爲我們coding的過程,我們coding出來的結果配得上我們的年齡了。

 

 

發佈了148 篇原創文章 · 獲贊 42 · 訪問量 195萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章