Socket又稱"套接字",應用程式通常通過"套接字"向網絡送出請求或者應答網絡請求,使主機間或者一台計算機上的程序間可以通訊。
Python中,我們用socket()函數來建立套接字,文法格式如下:
socket.socket([family[,type[, proto]]])
今天咱們先了解一下基本使用與方法,之後再看一個示例,好久之前寫的一個模拟ftp的put,get的示例,好了,瞅下面吧!
參數說明:
family: 套接字家族可以使AF_UNIX或者AF_INETtype: 套接字類型可以根據是面向連接配接的還是非連接配接分為SOCK_STREAM或SOCK_DGRAM,# SOCK_STREAM是基于TCP的,資料傳輸比較有保障。SOCK_DGRAM是基于UDP的,專門用于區域網路,protocol: 一般不填預設為0.
socket對象方法:
函數 | 描述 |
---|---|
伺服器端套接字 | |
s.bind() | 綁定位址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示位址。 |
s.listen() | 開始TCP監聽。backlog指定在拒絕連接配接之前,作業系統可以挂起的最大連接配接數量。該值至少為1,大部分應用程式設為5就可以了。 |
s.accept() | 被動接受TCP用戶端連接配接,(阻塞式)等待連接配接的到來 |
用戶端套接字 | |
s.connect() | 主動初始化TCP伺服器連接配接,。一般address的格式為元組(hostname,port),如果連接配接出錯,傳回socket.error錯誤。 |
s.connect_ex() | connect()函數的擴充版本,出錯時傳回出錯碼,而不是抛出異常 |
公共用途的套接字函數 | |
s.recv() | 接收TCP資料,資料以字元串形式傳回,bufsize指定要接收的最大資料量。flag提供有關消息的其他資訊,通常可以忽略。 |
s.send() | 發送TCP資料,将string中的資料發送到連接配接的套接字。傳回值是要發送的位元組數量,該數量可能小于string的位元組大小。 |
s.sendall() | 完整發送TCP資料,完整發送TCP資料。将string中的資料發送到連接配接的套接字,但在傳回之前會嘗試發送所有資料。成功傳回None,失敗則抛出異常。 |
s.recvfrom() | 接收UDP資料,與recv()類似,但傳回值是(data,address)。其中data是包含接收資料的字元串,address是發送資料的套接字位址。 |
s.sendto() | 發送UDP資料,将資料發送到套接字,address是形式為(ipaddr,port)的元組,指定遠端位址。傳回值是發送的位元組數。 |
s.close() | 關閉套接字 |
s.getpeername() | 傳回連接配接套接字的遠端位址。傳回值通常是元組(ipaddr,port)。 |
s.getsockname() | 傳回套接字自己的位址。通常是一個元組(ipaddr,port) |
s.setsockopt(level,optname,value) | 設定給定套接字選項的值。 |
s.getsockopt(level,optname[.buflen]) | 傳回套接字選項的值。 |
s.settimeout(timeout) | 設定套接字操作的逾時期,timeout是一個浮點數,機關是秒。值為None表示沒有逾時期。一般,逾時期應該在剛建立套接字時設定,因為它們可能用于連接配接的操作(如connect()) |
s.gettimeout() | 傳回目前逾時期的值,機關是秒,如果沒有設定逾時期,則傳回None。 |
s.fileno() | 傳回套接字的檔案描述符。 |
s.setblocking(flag) | 如果flag為0,則将套接字設為非阻塞模式,否則将套接字設為阻塞模式(預設值)。非阻塞模式下,如果調用recv()沒有發現任何資料,或send()調用無法立即發送資料,那麼将引起socket.error異常。 |
s.makefile() | 建立一個與該套接字相關聯的檔案 |
大家看煩了吧,撸碼哈!
server.py
from socket import *import osBasedir = os.getcwd() + '\server_file\\'def send_file(csock, filename): fp = filename if os.path.isabs(filename) else os.path.join(Basedir, filename) if not os.path.exists(fp): csock.send("error".encode('utf-8')) else: f_size = os.path.getsize(fp) csock.send(str(f_size).encode('utf-8')) with open(fp, 'rb') as f: print('start send file size is {}'.format(f_size)) r_data = bytes() while True: data = f.read(4096) r_data += data if len(r_data) == int(f_size): csock.send(r_data) print('\033[31mSend file ok !\033[0m') return return def recv_file(csock, filename): fp = filename if os.path.isabs(filename) else os.path.join(Basedir, filename) csock.send('start_upload'.encode('utf-8')) fsize = csock.recv(1024) sumsize = fsize.decode('utf-8') if len(sumsize) > 0: with open(fp, 'wb') as f: print('start save file :', fp) r_data = bytes() while True: # print(sumsize) ndata = csock.recv(4096) r_data += ndata # print(r_data) if len(r_data) == int(sumsize): f.write(r_data) print('save file ok') break return def sls_fun(): list_data = os.listdir(Basedir) return list_data def accept_write(ssock): csockfd, addres = ssock.accept() print('connect client \033[31m{}\033[0m...'.format(addres)) while True: data = csockfd.recv(1024) ndata = data.decode('utf-8') ndata = ndata.split() if ndata[0] == 'close': break elif ndata[0] == 'sls': list2 = sls_fun() csockfd.send(str(list2).encode('utf-8')) elif ndata[0] == 'put': recv_file(csockfd, ndata[1]) elif ndata[0] == 'get': send_file(csockfd, ndata[1]) else: break if __name__ == '__main__': sock = socket(AF_INET, SOCK_STREAM) sock.bind(('192.168.1.2', 8008)) sock.listen(5) print('waiting connect ...') accept_write(sock)
client.py
from socket import *import os, timeBasedir = os.getcwd() + '\client_file\\'def put_file(csock, filename, ncmd): if not os.path.isabs(filename): file_path = os.path.join(Basedir, filename) else: file_path = filename print(file_path) if not os.path.exists(file_path): print('本地沒有該檔案!') return else: csock.send(ncmd.encode('utf-8')) result = csock.recv(1024) if result.decode('utf-8') == 'start_upload': f_size = os.path.getsize(file_path) csock.send(str(f_size).encode('utf-8')) with open(file_path, 'rb') as f: print('start put file...') r_data = bytes() while True: data = f.read(4096) r_data += data if len(r_data) == int(f_size): csock.send(r_data) print('put file ok {}'.format(len(r_data))) break return def get_file(csock, filename, ncmd): csock.send(ncmd.encode('utf-8')) data = csock.recv(1024) if data.decode('utf-8') == 'error': print('file not found!') elif int(data.decode('utf-8')) > 0: sumsize = data.decode('utf-8') fp = os.path.join(Basedir, filename) print('start get file') with open(fp, 'wb') as f: rdata = bytes() while True: ndata = csock.recv(4096) rdata += ndata if len(rdata) == int(sumsize): f.write(rdata) print('\033[31mGet file ok !\033[0m') break return def ls_fun(): ls_data = os.listdir(Basedir) return ls_data def conn_s(csock): csock.connect(('192.168.1.2', 8008)) print('''connect server ... Please input command: ls : 列出用戶端檔案。 sls: 列出服務端檔案。 put fn:上傳‘fn’檔案。 get fn:下載下傳‘fn’檔案。''') while True: ncmd = input('>>>') cmd = ncmd.split() if not cmd or cmd[0] == 'ls': list1 = ls_fun() print(list1) elif cmd[0] == 'sls': csock.send(cmd[0].encode('utf-8')) sdata = csock.recv(4096) print(sdata.decode('utf-8')) elif cmd[0] == 'put' and cmd[1]: put_file(csock, str(cmd[1]), ncmd) elif cmd[0] == 'get' and cmd[1]: get_file(csock, str(cmd[1]), ncmd) elif cmd[0] == 'del' and cmd[1]: csock.send(cmd[0].encode('utf-8')) elif cmd[0] == 'sdel' and cmd[1]: csock.send(cmd[0].encode('utf-8')) elif cmd[0] == 'close': csock.send(cmd[0].encode('utf-8')) break else: pass if __name__ == '__main__': csock = socket(AF_INET, SOCK_STREAM) conn_s(csock)
講一下大概功能哈,先運作server.py,後運作client.py,在client端可以檢視當地檔案夾内的檔案,和server端的檔案夾内的檔案,可以put與get兩端的檔案,這是最初學習socket時弄的,大家有問題留言哈!,你們的時間都是很寶貴的,這裡就不留大家吃飯了哈,