套接字工做流程
先從服務器端提及。服務器端先初始化Socket,而後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端鏈接。在這時若是有個客戶端初始化一個Socket,而後鏈接服務器(connect),若是鏈接成功,這時客戶端與服務器端的鏈接就創建了。客戶端發送數據請求,服務器端接收請求並處理請求,而後把迴應數據發送給客戶端,客戶端讀取數據,最後關閉鏈接,一次交互結束。python
Socket Families(地址簇)
socket.
AF_UNIX unix本機進程間通訊
服務器
socket.
AF_INET IPV4
併發
socket.
AF_INET6 IPV6
ssh
Socket Types
socket.
SOCK_STREAM #for tcp
socket
socket.
SOCK_DGRAM #for udp
tcp
Socket 參數
s.bind(address) 綁定(host,port)ide
s.listen(backlog) 開始監聽傳入鏈接。backlog指定在拒絕鏈接以前,能夠掛起的最大鏈接數量post
s.accept() 接受鏈接並返回(conn,address),其中conn是新的套接字對象,能夠用來接收和發送數據。address是鏈接客戶端的地址。spa
s.connect(address) address的格式爲元組(hostname,port)unix
s.setblocking(bool) 是否阻塞(默認True),若是設置False,那麼accept和recv時一旦無數據,則報錯。
s.close() 關閉套接字
s.recv(bufsize) bufsize指定最多能夠接收的數量
s.send(string) 將string中的數據發送到鏈接的套接字。返回值是要發送的字節數量,該數量可能小於string的字節大小。即:可能未將指定內容所有發送。
s.sendall(string) 將string中的數據發送到鏈接的套接字,但在返回以前會嘗試發送全部數據。成功返回None,失敗則拋出異常。
內部經過遞歸調用send,將全部內容發送出去。
s.settimeout(timeout) 設置套接字操做的超時期,timeout是一個浮點數,單位是秒。值爲None表示沒有超時期。通常,超時期應該在
剛建立套接字時設置,由於它們可能用於鏈接的操做(如 client 鏈接最多等待5s )
s.getpeername() 返回鏈接套接字的遠程地址。返回值一般是元組(ipaddr,port)
服務端
- 建立socket對象
- 綁定IP和端口 綁定 bind()
- 開始監聽連接 監聽 listen()
- 阻塞 , 等待客戶端成功鏈接 阻塞 accept()
- 接收請求數據 接收 recv()
- 處理併發送請求數據 發送 send()
- 關閉 close()
客戶端
- 建立socket對象
- 鏈接服務端 , 按照IP和端口鏈接 鏈接 connet()
- 發送請求數據 發送 send()
- 接收請求數據 接收 recv()
- 關閉 close()
簡單socket
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 重用ip和端口 ,但其它client只是掛起狀態。只有一個能交互
![](http://static.javashuo.com/static/loading.gif)
import socket # 建立socket對象 sock = socket.socket() # 綁定IP和端口,參數是一個元組(ip,port) sock.bind(('localhost', 8080)) # 開始監聽,最大掛起5個 sock.listen(5) # 阻塞,等待鏈接 conn,addr = sock.accept() # 接收請求數據,接收大小爲1024字節 content = conn.recv(1024) print(content.decode()) # 發送請求結果,必須以bytes類型 conn.send(b'jieshouwanbi') # 關閉連接 conn.close()
![](http://static.javashuo.com/static/loading.gif)
import socket # 建立socket對象 sock = socket.socket() # 創建連接 sock.connect(('localhost', 8080)) # 發送請求數據,必須以bytes類型 sock.send(b"hello") # 接收請求結果 content = sock.recv(1024) print(content.decode()) # 關閉套接字 sock.close()
SSH
![](http://static.javashuo.com/static/loading.gif)
1 import socket ,os 2 server = socket.socket() #建立socket對象 3 server.bind(('localhost',9999) ) #綁定ip和port 4 server.listen() #開始監聽 5 6 while True: 7 conn, addr = server.accept() #阻塞 等待鏈接 8 print("new conn:",addr) 9 while True: 10 print("等待新指令") 11 data = conn.recv(1024) #接收客戶端發過來的命令 12 if not data: 13 break 14 print("執行指令:",data) 15 cmd_res = os.popen(data.decode()).read() #執行客戶端發過來的命令,返回信息長度(接收字符串,執行結果也是字符串) 16 print("before send",len(cmd_res)) #信息的長度 17 if len(cmd_res) ==0: 18 cmd_res = "cmd has no output..." 19 20 conn.send( str(len(cmd_res.encode())).encode("utf-8") ) #先發命令執行的結果信息大小給客戶端 21 client_ack = conn.recv(1024) #防止粘包,客戶端ack 22 conn.send(cmd_res.encode("utf-8")) #發送信息 23 print("send done") 24 25 server.close()
![](http://static.javashuo.com/static/loading.gif)
1 import socket 2 client = socket.socket() 3 client.connect(('localhost',9999)) 4 5 while True: 6 cmd = input(">>:").strip() #輸入命令 7 if len(cmd) == 0: continue 8 client.send(cmd.encode("utf-8")) #發送命令給server端 9 cmd_res_size = client.recv(1024) #接受server端發過來的命令結果信息長度 10 print("命令結果大小:",cmd_res_size) 11 client.send("準備接受".encode('utf-8')) #防止粘包 12 received_size = 0 #已經接受數據的大小 13 received_data = b'' 14 while received_size < int(cmd_res_size.decode()): 15 data = client.recv(1024) #只要小於,就一直接收 16 received_size += len(data) #每次收到的有可能小於1024,因此 17 必須用len判斷 18 #print(data.decode()) 19 received_data += data 20 else: 21 print("cmd res receive done...",received_size) 22 print(received_data.decode()) 23 24 25 client.close()
ftp傳文件
1
2
3
4
5
6
7
8
9
|
ftp server
1.
讀取文件名
2.
檢測文件是否存在
3.
打開文件
4.
檢測文件大小
5.
發送文件大小給客戶端
6.
等客戶端確認
7.
開始邊讀邊發數據
8.
發送md5
|
![](http://static.javashuo.com/static/loading.gif)
1 import socket ,os 2 server = socket.socket() 3 server.bind(('localhost',9999)) 4 server.listen() 5 6 while True: 7 conn, addr = server.accept() 8 print("new conn:",addr) 9 while True: 10 print("等待新指令") 11 data = conn.recv(1024) 12 if not data: 13 print("客戶端已斷開") 14 break 15 cmd,filename = data.decode().split() 16 print(filename) 17 if os.path.isfile(filename): #判斷是不是文件 18 f = open(filename,"rb") #打開文件 19 file_size = os.stat(filename).st_size #文件大小 20 conn.send( str(file_size).encode() ) #send file size 防止粘包 21 conn.recv(1024) #wait for ack 22 for line in f: 23 conn.send(line) #開始發送 24 f.close() 25 print("send done") 26 27 server.close()
![](http://static.javashuo.com/static/loading.gif)
1 import socket 2 import hashlib 3 client = socket.socket() 4 client.connect(('localhost', 9999)) 5 6 while True: 7 cmd = input(">>:").strip() 8 if len(cmd) == 0: continue 9 10 if cmd.startswith("get"): #判斷是否以字符串‘get’ 開頭 11 client.send(cmd.encode()) #把須要下載的文件發給server端 12 server_response = client.recv(1024) #接收server端發過來的文件大小 13 print("servr response:", server_response) #打印文件大小 14 client.send(b"ready to recv file") #防止粘包 15 file_total_size = int(server_response.decode()) 16 received_size = 0 #已經接收的大小 17 filename = cmd.split()[1] 18 f = open(filename + ".new", "wb") #建立新文件 用於保存 19 20 while received_size < file_total_size: 21 if file_total_size - received_size > 1024: # 要收不止一次 22 size = 1024 23 else: # 最後一次了,剩多少收多少 24 size = file_total_size - received_size 25 print("last receive:", size) 26 27 data = client.recv(size) 28 received_size += len(data) 29 f.write(data) 30 # print(file_total_size,received_size) 31 else: 32 print("file recv done", received_size, file_total_size) 33 f.close() 34 client.close()
![](http://static.javashuo.com/static/loading.gif)
1 import hashlib 2 import socket ,os,time 3 server = socket.socket() 4 server.bind(('localhost',9999)) 5 server.listen() 6 while True: 7 conn, addr = server.accept() 8 print("new conn:",addr) 9 while True: 10 print("等待新指令") 11 data = conn.recv(1024) 12 if not data: 13 print("客戶端已斷開") 14 break 15 cmd,filename = data.decode().split() 16 print(filename) 17 if os.path.isfile(filename): 18 f = open(filename,"rb") 19 m = hashlib.md5() 20 file_size = os.stat(filename).st_size 21 conn.send( str(file_size).encode() ) #send file size 22 conn.recv(1024) #wait for ack 23 for line in f: 24 m.update(line) 25 conn.send(line) 26 print("file md5", m.hexdigest()) 27 f.close() 28 conn.send(m.hexdigest().encode()) #send md5 29 print("send done") 30 31 server.close()
![](http://static.javashuo.com/static/loading.gif)
1 import socket 2 import hashlib 3 client = socket.socket() 4 client.connect(('localhost', 9999)) 5 6 while True: 7 cmd = input(">>:").strip() 8 if len(cmd) == 0: continue 9 if cmd.startswith("get"): 10 client.send(cmd.encode()) 11 server_response = client.recv(1024) 12 print("servr response:", server_response) 13 client.send(b"ready to recv file") 14 file_total_size = int(server_response.decode()) 15 received_size = 0 16 filename = cmd.split()[1] 17 f = open(filename + ".new", "wb") 18 m = hashlib.md5() 19 20 while received_size < file_total_size: 21 if file_total_size - received_size > 1024: # 要收不止一次 22 size = 1024 23 else: # 最後一次了,剩多少收多少 24 size = file_total_size - received_size 25 print("last receive:", size) 26 27 data = client.recv(size) 28 received_size += len(data) 29 m.update(data) 30 f.write(data) 31 print(file_total_size,received_size) 32 else: 33 new_file_md5 = m.hexdigest() 34 print("file recv done", received_size, file_total_size) 35 f.close() 36 server_file_md5 = client.recv(1024) 37 print("server file md5:", server_file_md5) 38 print("client file md5:", new_file_md5) 39 40 client.close()