問題:python
什麼是七層模型
tcp 和udp區別
三次握手和四次揮手
**************************************************web
tcp 數據傳輸:後端
recv會不斷的取出緩衝區中內容,若是一次沒有拿完,那麼下次會繼續收取沒拿完的消息;安全
tcp 粘包服務器
tcp粘包指的是<發送方> 發送若干次數據的時候,由於是數據流的傳輸方式,致使數據粘在一塊兒,<接收方>一次將屢次發送的數據一塊兒接收,傳輸接收數據的粘連;網絡
粘包是tcp傳輸特有的現象,由於tcp傳輸沒有消息邊界。 若是是發送連續的內容,好比文件等,則粘包沒有影響。若是是每次發送爲單獨須要處理內容則須要處理粘包;多線程
如何處理粘包?架構
1,將消息格式化;併發
2,發送消息的同時發送一個消息長度標識;socket
3,讓消息的發送延遲,使接收端每次都可以有時間接收一個消息;
UDP數據表套接字服務端:SERVER
(面向無鏈接的不可靠的傳輸服務)
1,建立數據報套接字;
2,綁定本地IP和端口;
3,收發消息;
recvfrom(BUFFERSIZE)
功能:在udp中接收消息;
參數: buffersize 表示一次最多能夠接收多少字節的消息;
返回值:data:接收到的消息;
addr :表示從哪一個客戶端接收到的消息;
sendto(data, addr)
功能: 向一個網絡終端發送消息;
參數:data要發送的消息(bytes)
addr 發送對象的地址;
4,關閉套接字
import sys
sys.argv : 將命令行內容收集爲一個列表,每一個元素是命令行中的一項;
(命令行傳入的內容均爲str格式; 命令行內容以空格做爲分隔,引號能夠合成一個總體;)
#!/usr/bin/python3 import sys print(sys.argv[1]) print(sys.argv[2]) #### # python3 sys_argv.py 192.168.1.10 8888 192.168.1.10 8888
UDP客戶端:CLIENT
1,建立數據報套接字
2,消息收發;
3,關閉套接字;
(recvfrom每次只能接收一個數據包,若是數據包的大小超過recvfrom的設置大小,則會出現數據丟失;)
########udp_server########## from socket import * import sys from time import ctime #從命令行傳入IP和端口 HOST = sys.argv[1] PORT = int(sys.argv[2]) ADDR = (HOST,PORT) BUFFERSIZE = 5 #建立數據報套接字 sockfd = socket(AF_INET,SOCK_DGRAM) #綁定本地IP和端口 sockfd.bind(ADDR) #收發消息 while True: data,addr = sockfd.recvfrom(BUFFERSIZE) print("recv from ",addr,':',data.decode()) sockfd.sendto\ (("在 %s 接受到你的消息"%ctime()).encode(),addr) #關閉套接字 sockfd.close() ############udp_client############## from socket import * import sys #從命令行傳入服務器的IP和端口 HOST = sys.argv[1] PORT = int(sys.argv[2]) ADDR = (HOST,PORT) BUFFERSIZE = 1024 #建立數據報套接字 sockfd = socket(AF_INET,SOCK_DGRAM) #消息收發 while True: data = input("消息>>") #輸入空客戶端退出 if not data: break #此處發送消息給服務器 sockfd.sendto(data.encode(),ADDR) data,addr = sockfd.recvfrom(BUFFERSIZE) print("從服務器接收:",data.decode()) #關閉套接字 sockfd.close() ############### python3 udp_client.py 192.168.1.112 8888 message>> a SERVER recvfrom...: In Sun Jul 1 17:50:05 2018 recvfrom your messages #### # python3 udp_server.py 192.168.1.112 8888 recvfrom: ('192.168.1.112', 56956) : a
總結tcp和udp的區別:
1,tcp是有鏈接的,udp是無鏈接的
2,tcp有三次握手四次揮手的過程;而udp沒有;
3,tcp是以數據流傳輸數據,會有粘包;udp是數據報的形式傳輸數據,沒有粘包;
4,tcp的鏈接須要消耗必定的資源,相比之下udp資源消耗少;
5,tcp保證數據的可靠性,udp不保證;
6,tcp須要listen accept connect; 而 udp 不須要這些操做;
socket模塊
套接字屬性
getpeername()
功能:用作服務器鏈接套接字,查看鏈接的客戶端地址;
getsockname()
功能: 獲取套接字對應的綁定的地址和端口;
s.type 套接字類型
fileno()
功能:獲取套接字的文件描述符號碼;
文件描述符:系統會給進程中的每一個IO操做對象匹配一個 >=0 的正整數做爲標號,咱們稱之爲該IO操做的文件描述符。一個進程中的全部IO的文件描述符不會重複;
setsockopt(level, optname, value)
功能: 設置套接字選項,能夠增長或改變套接字的功能;
參數:level 要定義的選項類型;
例如: SOL_SOCKET 、 IPPROTO_IP、 IPPROTO_TCP
optname 每種類型都有具體的選項,根據具體需求選擇選項 , 進行設置;
例如: SOL_SOCKET ---> SO_REUSERADDR (#將端口號設置爲當即重用(SOL_SOCKET,SO_REUSEADDR,1) )
value 將選擇的現象設置爲何值;
getsockopt(level, optname)
功能:獲取相應選項的值
參數:level 要獲取的選項類型
optname 每種類型都有具體的選項,根據具體需求選擇要獲取的選項;
返回值:獲取到的值;
######tcp_server##### from socket import * import time HOST = '192.168.1.112' PORT = 8888 ADDR = (HOST,PORT) BUFFERSIZE = 1024 sockfd = socket(AF_INET,SOCK_STREAM) print("您的套接字是:",sockfd.type) print("sockfd 的 file num:",sockfd.fileno()) #將端口號設置爲當即重用 sockfd.setsockopt\ (SOL_SOCKET,SO_REUSEADDR,1) print("獲取選項值:",sockfd.\ getsockopt(SOL_SOCKET,SO_REUSEADDR)) sockfd.bind(ADDR) sockfd.listen(5) print("您的套接字地址是:",sockfd.getsockname()) while True: print("wait for connect......") conn,addr = sockfd.accept() #使用getpeername獲取連接的客戶端的地址 print("connect from ",conn.getpeername()) while True: data = conn.recv(BUFFERSIZE) if not data: break print("接受到:",data.decode()) n = conn.send(b"Recv your message\n") print("發送了 %d 字節的數據"%n) conn.close() # 表示和客戶端斷開鏈接 sockfd.close() # 不能再使用sockfd ######tcp_client###### cat tcp_client.py #!/usr/local/bin/python3 from socket import * import time HOST = '192.168.1.112' PORT = 8888 ADDR = (HOST,PORT) connfd = socket(AF_INET,SOCK_STREAM) connfd.connect(ADDR) while True: data = input('send>>>') if not data: break connfd.sendall(data.encode()) data = connfd.recv(1024) print('client recv:',data.decode()) connfd.close()
socket服務器模型:
硬件服務器 : 計算機主機 IBM HP
集成 分佈式
軟件服務器 : 網絡服務器,提供後端邏輯服務和請求處理的程序集合及架構
例如 web服務器等
服務器架構 c/s b/s 服務器的組織形式
服務器追求 : 更快速, 更安全,併發量更大
fork
1, 建立套接字 綁定 監聽;
2,接收客戶端鏈接請求 建立新的進程;
3,主進程繼續接收下一個客戶端鏈接請求,子進程處理客戶端事件;
4, 有客戶端斷開,則關閉響應的子進程;
##########fork_tcp_server############ from socket import * import os import signal #有客戶端斷開則關閉相應的子進程 def handler(c): while True: data = c.recv(BUFFERSIZE).decode() if not data: break print("服務器收到:",data) c.send(b'receive your message') c.close() os._exit(0) #建立套接字 綁定 監聽 HOST = '192.168.1.112' PORT = 8888 ADDR = (HOST,PORT) BUFFERSIZE = 1024 #建立tcp套接字 s = socket() s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) s.bind(ADDR) s.listen(5) #作殭屍進程的處理 signal.signal(signal.SIGCHLD,signal.SIG_IGN) #接收客戶端鏈接請求 建立新的進程 while True: try: c,addr = s.accept() except KeyboardInterrupt: print("服務器結束") s.close() os._exit(0) except Exception: continue print("接收到客戶端連接 >",c.getpeername()) pid = os.fork() if pid < 0: print("建立子進程失敗") continue #子進程處理客戶端事件 elif pid == 0: s.close() print('處理客戶端請求事件') handler(c) # 處理客戶端的函數 #主進程繼續接收下一個客戶端鏈接請求 else: c.close() continue #########tcp_client######## # cat tcp_server.py #!/usr/local/bin/python3 from socket import * HOST = '127.0.0.1' PORT = 8888 ADDR = (HOST,PORT) BUFFERSIZE = 1024 sockfd = socket(AF_INET, SOCK_STREAM) sockfd.bind(ADDR) sockfd.listen(5) while True: print('wait for connect....') conn,addr = sockfd.accept() print('connect from',addr) while True: data = conn.recv(BUFFERSIZE) if not data: break print('connect:',data.decode()) n = conn.send(b'Recv your message.\n') print('send.. %d'%n) conn.close() sockfd.close()
threading
1, 建立套接字 , 綁定, 監聽;
2,接收客戶端鏈接請求, 建立新的線程;
3,主線程繼續接收下一個客戶端鏈接請求;分支線程處理客戶端事件;
練習
########threading_tcp_server####### from socket import * import threading import os #有客戶端斷開則關閉相應的子線程 def handler(c): while True: data = c.recv(BUFFERSIZE).decode() if not data: break print("服務器收到:",data) c.send(b'receive your message') c.close() #建立套接字 綁定 監聽 HOST = '127.0.0.1' PORT = 8888 ADDR = (HOST,PORT) BUFFERSIZE = 1024 #建立tcp套接字 s = socket() s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) s.bind(ADDR) s.listen(5) #接收客戶端鏈接請求 建立新的線程 while True: try: c,addr = s.accept() except KeyboardInterrupt: print("服務器結束") s.close() os._exit(0) except Exception: continue print("接收到客戶端連接 >",c.getpeername()) #分支線程處理客戶端事件 t = threading.Thread\ (target = handler,args = (c,)) t.setDaemon(True) t.start() #主線程繼續接收下一個客戶端鏈接請求 ##########tcp_client################# # cat tcp_client.py #!/usr/local/bin/python3 from socket import * import time HOST = '127.0.0.1' PORT = 8888 ADDR = (HOST,PORT) connfd = socket(AF_INET,SOCK_STREAM) connfd.connect(ADDR) while True: data = input('send>>>') if not data: break connfd.sendall(data.encode()) data = connfd.recv(1024) print('client recv:',data.decode()) connfd.close()
socketserver模塊 (python2 SocketServer)
'DatagramRequestHandler',
'ForkingMixIn',
'ForkingTCPServer',
'ForkingUDPServer',
'StreamRequestHandler',
'TCPServer',
'ThreadingMixIn',
'ThreadingTCPServer',
'ThreadingUDPServer',
'UDPServer',
三部分:
多進程/多線程 TCP/UDP streamhandler/datagramhandler
ForkingMixIn TCPServer StreamRequestHandler
ThreadingMixIn UDPServer DatagramRequestHandler
組合以下:
‘ThreadingTCPServer’ = ThreadingMixIn + TCPServer
‘ThreadingUDPServer’ = ThreadingMixIn + UDPServer
ForkingTCPServer = ForkingMixIn + TCPServer
ForkingUDPServer = ForkingMixIn + UDPServer
步驟:
1, 建立服務器類;
2,建立處理類;
3,使用建立的服務器類來生產服務器;
# fork + tcp 併發
########socket_server######### # fork + tcp 併發 from socketserver import * #建立服務器類 class Server(ThreadingMixIn,TCPServer): pass # class Server(ForkingTCPServer): # pass #建立處理類 class Handler(StreamRequestHandler): #當有客戶端連接時候調用該函數自動處理 #客戶段請求事件 def handle(self): print("connect from ",self.client_address) while True: #self.request 爲tcp中爲咱們自動生成的 #和客戶端交互的套接字 data = self.request.recv(1024).decode() if not data: break print("服務器收到:",data) self.request.send(b'receive your message') #使用建立的服務器類來生產服務器 server = Server(('172.60.50.218',9999),Handler) #運行服務器 server.serve_forever() #########tcp_client######## # cat tcp_client.py #!/usr/local/bin/python3 from socket import * import time HOST = '127.0.0.1' PORT = 8889 ADDR = (HOST,PORT) connfd = socket(AF_INET,SOCK_STREAM) connfd.connect(ADDR) while True: data = input('send>>>') if not data: break connfd.sendall(data.encode()) data = connfd.recv(1024) print('client recv:',data.decode()) connfd.close()
# fork + udp
##########fork_udp_server############# # fork + udp from socketserver import * class Server(ForkingUDPServer): pass class Handler(DatagramRequestHandler): #udp無鏈接因此request的含義不一樣 def handle(self): data = self.rfile.readline() print("接受到了:",data.decode()) self.wfile.write(b"receive message") server = Server(('0.0.0.0',8888),Handler) server.serve_forever() ###########udp_client############## # cat udp_client.py #!/usr/local/bin/python3 from socket import * import sys HOST = sys.argv[1] PORT = int(sys.argv[2]) ADDR = (HOST,PORT) BUFFERSIZE = 1024 sockfd = socket(AF_INET, SOCK_DGRAM) while True: data = input("message>> ") if not data: break sockfd.sendto(data.encode(),ADDR) data,addr = sockfd.recvfrom(BUFFERSIZE) print('SERVER recvfrom...: ', data.decode()) sockfd.close()
思考:ftp傳輸