1. 程式人生 > >史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

 

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

 

import socket

sk= socket.socket()#建立物件

sk.bind(('127.0.0.1',9999,))#繫結IP和埠,以一個元組的方式傳進去

sk.listen(5)#在前面連結已經建立的情況下,後面最多讓五個人等待

while True:#讓伺服器端處於可以永遠處於接受客戶端請求的狀態

conn,address=sk.accept()

print(conn,address)

私信菜鳥 007 獲取最全教程合集!

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

 

obj.connect(('127.0.0.1',9999,))#連結服務端

obj.close()#連結之後關閉

我們先讓伺服器端啟動,然後再啟動客戶端,結果如圖所示

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

 

<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9999), raddr=('127.0.0.1', 36126)> ('127.0.0.1', 36126)

<socket.socket fd=5, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9999), raddr=('127.0.0.1', 36128)> ('127.0.0.1', 36128)

<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9999), raddr=('127.0.0.1', 36130)> ('127.0.0.1', 36130)

成功打印出了每次的連結,以及客戶端的IP以及埠號

(2)基於socket實現簡單的傳送訊息

#伺服器端

import socket

sk= socket.socket()

sk.bind(('127.0.0.1',9999,))#繫結IP和埠,以一個元組的方式傳進去

sk.listen(5)#在前面連結已經建立的情況下,後面最多讓五個人等待

while True:#讓伺服器端處於可以永遠處於接受客戶端請求的狀態

conn,address=sk.accept()#基於conn這個連結傳送東西

conn.sendall(bytes('有空來Linux公社www.linuxidc.com天天給你新知識',encoding='utf-8'))#Python3要用bytes型別,傳送位元組

'''建立一次連結,伺服器就傳送這個欄位'''

print(conn,address)

然後用是客戶端程式碼

#客戶端

import socket

obj =socket.socket()

'''相對於客戶端,制定要連結誰就好了

'''

obj.connect(('127.0.0.1',9999,))#連結服務端

'''

客戶端去連結服務端,如果伺服器端沒有返回訊息給客戶端,則客戶端會一直

在recv狀態,一直等待伺服器的訊息

'''

result1= obj.recv(2014)#表示最多接收1024個位元組,超過了下次接收、

result2= str(result1,encoding='utf-8')

print(result2)

obj.close()#連結之後關閉

當啟動一次客戶端建立一次連結,就會收到訊息,結果如圖

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

 

(3)基於socket實現聊天機器人

#伺服器端

import socket

sk= socket.socket()

sk.bind(('127.0.0.1',9999,))#繫結IP和埠,以一個元組的方式傳進去

sk.listen(5)#在前面連結已經建立的情況下,後面最多讓五個人等待

while True:#讓伺服器端處於可以永遠處於接受客戶端請求的狀態

conn,address=sk.accept()#基於conn這個連結傳送東西

conn.sendall(bytes('你好www.linuxidc.com,連結已經建立',encoding='utf-8'))#Python3要用bytes型別,傳送位元組

# '''建立一次連結,伺服器就先發送這個欄位'''

while True:#讓通訊狀態不中斷

ret_bytes = conn.recv(1024)

ret_str = str(ret_bytes,encoding='utf-8')

if ret_str =='q':#如果收到q,則終止連結

break

conn.sendall(bytes(ret_str+' 已收到該資訊',encoding='utf-8'))

#print(conn,address)

下面是客戶端程式碼

#客戶端

import socket

obj =socket.socket()

'''相對於客戶端,制定要連結誰就好了

'''

obj.connect(('127.0.0.1',9999,))#連結服務端

'''

客戶端去連結服務端,如果伺服器端沒有返回訊息給客戶端,則客戶端會一直

在recv狀態,一直等待伺服器的訊息

'''

result1= obj.recv(2014)#表示最多接收1024個位元組,超過了下次接收、

result2= str(result1,encoding='utf-8')

print(result2)

while True:

data = input('請輸入你要傳送的內容:')

if data == 'q':

obj.sendall(bytes(data, encoding='utf-8'))

print('連結斷開')

break

else:

obj.sendall(bytes(data,encoding='utf-8'))

rec_byte = obj.recv(1024)#發了之後,接收資訊

rec_str = str(rec_byte,encoding='utf-8')

print(rec_str)

obj.close()#連結之後關閉

結果如圖所示

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

 

(4)利用socket傳送圖片檔案

#伺服器端

import socket

sk= socket.socket()

sk.bind(('127.0.0.1',9999,))#繫結IP和埠,以一個元組的方式傳進去

sk.listen(5)#在前面連結已經建立的情況下,後面最多讓五個人等待

while True:#

conn,address= sk.accept()

conn.sendall(bytes('連結已建立,可以傳送資料了',encoding='utf-8'))

file_size = str(conn.recv(1024),encoding='utf-8')#接收檔案大小

print('接收的檔案位元組數:'+file_size)

total_size = int(file_size)

has_recv = 0#預設已接收了0個位元組

f = open('linuxidc.com.png','wb')

#先接收檔案大小,再開始接收檔案

while True:

if total_size ==has_recv:#如果已接收的檔案大小與客戶端傳送的一樣大,則表示已經接收完畢

break

data = conn.recv(1024)

f.write(data)

has_recv +=len(data)

print('檔案接收成功')

f.close()

下面是客戶端

#客戶端

import os

import socket

obj =socket.socket()

obj.connect(('127.0.0.1',9999,))#連結服務端

'''

客戶端去連結服務端,如果伺服器端沒有返回訊息給客戶端,則客戶端會一直

在recv狀態,一直等待伺服器的訊息

# '''

#obj.sendall(bytes('你好',encoding='utf-8'))

ret_bytes = obj.recv(1024)

ret_str = str(ret_bytes,encoding='utf-8')

print(ret_str)

#傳送檔案大小

size=os.stat('linuxidc.png').st_size#獲取檔案大小

obj.sendall(bytes(str(size),encoding='utf-8'),)#檔案大小的int型,要先轉化為字串

with open('linuxidc.png','rb')as f:

for line in f:

obj.sendall(line)

obj.close()

結果如圖

進群:960410445  即可獲取原始碼!

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!

 

(5)socket粘包問題

傳送檔案需要依賴雙方的緩衝區,就是我們先把檔案寫到緩衝區,然後再發送過去,但是我們一般不知道什麼時候發過去,這容易造成粘包問題。例如上面的例子,客戶端先發送檔案大小,然後讀檔案寫進緩衝區,假如檔案讀取特別快,第一次傳送過去的可能既有檔案大小又有檔案內容,造成錯誤,這叫粘包,簡而言之就是收到的資訊比原本應收的多。

那麼怎麼解決粘包問題呢,通過傳送以及接收確認包,還是以上面的例子說明,客戶在傳送檔案大小之後不要馬上傳送檔案,先recv接收一下,等待伺服器傳送已收到檔案大小的確認包之後,再讀取檔案、傳送檔案,這樣檔案的傳送和之前資料的傳送就

完全獨立開來了。

#伺服器端

import socket

sk= socket.socket()

sk.bind(('127.0.0.1',9999,))#繫結IP和埠,以一個元組的方式傳進去

sk.listen(5)#在前面連結已經建立的情況下,後面最多讓五個人等待

while True:#

conn,address= sk.accept()

conn.sendall(bytes('連結已建立,可以傳送資料了',encoding='utf-8'))

file_size = str(conn.recv(1024),encoding='utf-8')#接收檔案大小

print('接收的檔案位元組數:'+file_size)

total_size = int(file_size)

has_recv = 0#預設已接收了0個位元組

conn.sendall(bytes('檔案大小已收到,可以開始傳送資料了',encoding='utf-8'))#解決粘包問題,已經收到了檔案大小,後面就可以單獨發文件了

f = open('linuxidc.com.png','wb')

#先接收檔案大小,再開始接收檔案

while True:

if total_size ==has_recv:#如果已接收的檔案大小與客戶端傳送的一樣大,則表示已經接收完畢

break

data = conn.recv(1024)

f.write(data)

has_recv +=len(data)

print('檔案接收成功')

f.close()

下面是客戶端

#客戶端

import os

import socket

obj =socket.socket()

obj.connect(('127.0.0.1',9999,))#連結服務端

'''

客戶端去連結服務端,如果伺服器端沒有返回訊息給客戶端,則客戶端會一直

在recv狀態,一直等待伺服器的訊息

# '''

#obj.sendall(bytes('你好www.linuxidc.com',encoding='utf-8'))

ret_bytes = obj.recv(1024)

ret_str = str(ret_bytes,encoding='utf-8')

print(ret_str)

#傳送檔案大小

size=os.stat('linuxidc.png').st_size#獲取檔案大小

obj.sendall(bytes(str(size),encoding='utf-8'),)#檔案大小的int型,要先轉化為字串

ack_packet=obj.recv(1024)

print(str(ack_packet,encoding='utf-8'))

with open('linuxidc.png','rb')as f:

for line in f:

obj.sendall(line)

obj.close()

史上最全socket模組詳解!沒有學不會的模組!只有學不學的模組!