1. 程式人生 > >python socket程式設計---從使用Python開發一個Socket示例說到開發者的思維和習慣問題

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. HOST='192.168.0.37'
  3. PORT=50000
  4. BUFFER=4096
  5. sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
  6. sock.bind((HOST,PORT)) 
  7. sock.listen(0
  8. print('tcpServer listen at: %s:%s\n\r' %(HOST,PORT)) 
  9. whileTrue
  10.   client_sock,client_addr=sock.accept() 
  11.   print('%s:%s connect' %client_addr) 
  12.   whileTrue
  13.     recv=client_sock.recv(BUFFER
  14.     ifnot recv: 
  15.       client_sock.close() 
  16.       break
  17.     print('[Client %s:%s said]:%s' % (client_addr[0],client_addr[1],recv)) 
  18.     client_sock.send('tcpServer has received your message'
  19. sock.close() 

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

下面是對應的客戶端程式碼

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

下面是udpServer的程式碼

  1. import socket 
  2. HOST='192.168.0.37'
  3. PORT=50001
  4. BUFFER=4096
  5. sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 
  6. sock.bind((HOST,PORT)) 
  7. #sock.listen(0)
  8. print('tcpServer listen at: %s:%s\n\r' %(HOST,PORT)) 
  9. whileTrue
  10.   #client_sock,client_addr=sock.accept()
  11.   #print('%s:%s connect' %client_addr)
  12.   whileTrue
  13.     recv,client_addr=sock.recvfrom(BUFFER) 
  14.     ifnot recv: 
  15.       break
  16.     print('[Client %s:%s said]:%s' % (client_addr[0],client_addr[1],recv)) 
  17.     sock.sendto('tcpServer has received your message',client_addr) 
  18. 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. import socket 
  4. HOST='192.168.0.37'
  5. PORT=50001
  6. BUFFER=4096
  7. sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 
  8. sock.connect((HOST,PORT)) 
  9. sock.send('hello, tcpServer!'
  10. recv=sock.recv(BUFFER) 
  11. print('[tcpServer said]: %s' % recv) 
  12. sock.close() 

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

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

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

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

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