Python之路PythonNet,第二篇,網絡2

pythonnet   網絡2

問題: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
View Code

 

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
View Code

 

總結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()
View Code

 

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()
View Code

 

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()
View Code

 

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()
View Code

 

# 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() 
View Code

 

思考:ftp傳輸

相關文章
相關標籤/搜索