~~網絡編程(四):socket套接字~~


進擊のpython

*****

網絡編程——socket


socket的中文意思叫做套接字,socket方法其實也叫套接字方法

我們研究過TCP/UDP協議,但是要是讓我們自己搭建,就十分困難了

而這時候,socket就出來了

socket他是存在在應用層和傳輸層之間的一堆接口

他把復雜的協議都封裝好了,你想用的時候,直接調用就行

就跟我們寫模塊一樣,把麻煩的代碼寫進去,等到用的時候只需要調用就行了

那你想想,咱們在研究模塊的時候,是不是學會方法怎么用就行??

那咱們學套接字方法,也是學會方法就行


我要是想給你打電話的話應該是怎么個過程?

# 首先我得有電話
# 輸入想打的電話
# 等待你接聽
# 跟你bb兩句
# 聽你bb兩句

那你接電話呢?

# 首先你得有電話
# 你還得有電話號碼
# 然后你得有電話線
# 等着接電話
# 鈴響接電話
# 聽你bb兩句

沒問題吧!

那我要是想寫成socket通信呢?


首先我得先創建兩個py文件是吧,通信嘛,當然要兩個:客戶端和服務端

然后要在兩個文件都調用socket模塊是吧

接下來就繼續吧!

解釋一下啊,socket里面的兩個屬性,第一個是套接字的類型,我們這個是基於網絡的嘛,所以是AF_INET

第二個是你數據的傳輸方式,SOCK_STREAM是流式傳輸,也就是TCP協議

在這我們要學習一個方法 bind 綁定,因為是手機綁定,所以是phone.bind

里面要添加一個元組參數 IP 和 端口

其中ip 我設置的是127.0.0.1,代表着本機的意思,我這不是要在自己電腦上操作嘛

端口最大到65535 其中,1-1024 是系統的端口,1024之后的就是應用的了,你隨便選個就行

這里就是又一個方法了 listen 監聽

里面要傳一個參數,這個5是什么意思呢?

我這個電話接通的時候,別人又給我打電話,我也不能掛了啊

那這種狀態可以維持幾個手機同時給我打電話呢?5個

那最后,我就開始等電話了是吧


那客戶端呢?是不是要買手機啊我用綁定ip嘛?

換句話說我用手機綁定手機卡,說只能用這個手機的這張卡才能給你打電話???

這顯然不對啊,所以,客戶端不用綁定

![1565065172405](D:\python 學習筆記\assets\1565065172405.png)

客戶端的撥號,用到了connet方法,里面放一個元組參數,元組由服務端的ip和端口構成

那我要是運行,是不是應該先運行服務端,再運行客戶端.這個能理解吧

那我們執行一下

看到了吧,這就算是連接上了,那我們看看我們拿的是什么東西

(<socket.socket fd=484, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 52621)>, ('127.0.0.1', 52621))

首先可以肯定這是個元組是吧,第一個元素是個什么東西?是不是套接字對象啊

第二個元素呢?是不是客戶端的ip以及端口信息啊

那我們是不是可以通過解構的方式把這兩個信息拿到啊

connet, client_addr = phone.accept()

那你說我這是不是就算是拿到了管道啊,那我有了管道了,我是不是就可以進行傳輸了啊


那我就可以收信息了,怎么收?又用到一個方法recv

connet.recv(1024)

它里面要傳個參數,傳接受的最大字節數

你給我傳一個,我就收一個,你要是給我傳1025個,我也收1024個

至於為什么是1024呢?我們后面說,你現在就先這么寫

那我要是發消息呢?send方法

connet.send()

里面傳發送的東西

打完電話就該掛電話了對吧

connet.close()

掛完電話是不是就關機了啊

phone.close()

那服務端完事了,客戶端是不是也應該寫點什么了

服務端是接收-發送

那我客戶端是不是應該是發送-接收

客戶端發送怎么寫?send

phone.send("hello".encode("utf-8"))

別忘了把編碼綴上

接收呢??recv

k = phone.recv(1024)
print(k)

然后呢?關機!

phone.close()

行啦!我們來看看寫完的長什么樣

執行一下吧(別忘了先執行服務端,再執行客戶端)

這樣,就完成了一個簡單的C/S結構!

話不多說,自己多敲幾遍


正常人誰那么搞啊,不都是有來言有去語的嗎

那我們是不是就應該用循環來搞這個需求

循環放在哪呢?我們不是要循環收發這個過程嘛

那我們就應該循環收發信息這一塊的代碼啊

# 服務端
import socket

# 買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 綁定手機卡
phone.bind(("127.0.0.1", 8080))

# 開機
phone.listen(5)

# 等電話
connet, client_addr = phone.accept()

# 收發消息
while 1:
    k = connet.recv(1024)
    print(f'從客戶端接收的消息:{k}')
    connet.send(k.upper())

# 掛電話
connet.close()

# 關機
phone.close()
# 客戶端
import socket

# 買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 撥號
phone.connect(("127.0.0.1", 8080))

# 發收信息
while 1:
    msg = input(">>>")
    phone.send(msg.encode("utf-8"))
    k = phone.recv(1024)
    print(f"從服務端接收的消息:{k}")

# 關閉
phone.close()
# 服務端
從客戶端接收的消息:b'as'
從客戶端接收的消息:b'ds'
從客戶端接收的消息:b'fa'

# 客戶端
>>>as
從服務端接收的消息:b'AS'
>>>ds
從服務端接收的消息:b'DS'
>>>fa
從服務端接收的消息:b'FA'
>>>

還有一點就是想說,你們在調試的時候沒遇到這個報錯嗎?

OSError:[Errno 48] Address already in use

這個問題就是說你剛關那個程序,然后系統還沒有把你定義的端口給回收,你就又用了,就會出這個錯誤

怎么解決呢?

一種辦法是修改客戶端和服務端的端口,但是你不覺得太傻逼了嗎?

所以還有另一種方法,就是在程序服務端綁定ip和端口下面添加一段這個代碼

phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

這樣就沒事了,這個就是如果我發現這個端口被占用了,我就重新啟用他


不是,那你們沒有遇到bug嘛?

比如我在服務端直接敲回車,結果是什么???

你會發現你的程序執行不了了

那是誰的問題呢?是沒發過去還是沒接過來呢?

我們在send的下面寫一個打印,發現可以被打印,那就說明我發過去了

而當我在接收的下面寫一個打印,發現沒有被打印,說明我沒有接受到

而且服務端也沒有執行原來有的print

那就說明是我發過去了,但是他什么都沒有接收,所以她始終都在接受的這個位置等我傳

也就是說空字符串是沒辦法單獨傳過去的,怎么解決這個問題呢?加個判斷就好了啊

if not msg:continue

這樣bug就沒了


還有問題!你在斷開客戶端的時候,你會發現,服務端報錯了!

ConnectionResetError: [WinError 10054] 遠程主機強迫關閉了一個現有的連接。

這是我們不能忍的啊,我不跟你鏈接了,你就報錯?這不符合常識

所以我們就可以用異常捕獲來處理

 try:
        k = connet.recv(1024)
        print(f'從客戶端接收的消息:{k}')
        connet.send(k.upper())
    except ConnectionResetError:
        break

這樣就沒問題了!

這里多說一句啊,我這個代碼是在windows里運行的,如果你是linux運行的

服務端是不會報錯的,他會不停的接收一個空,一直循環不報錯

這樣就會使程序變成死循環!,這是我們所不能接受的!

所以,在服務端加個判斷

if not k:break

這樣就萬無一失了!

畢竟正常人不會發送個空過來!


*有點東西*
*繼續深究*


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM