day19-網絡編程基礎(二)

今天沒有不少概念性的東西,主要是方法性的東西以及編程的一些方法吧編程

今日份目錄json

1.UDP傳輸的特色以及實驗小程序

2.UTP與UDP傳輸的區別服務器

3.基於tcp的low版帶驗證功能的FTP小程序網絡

4.基於socketserver的多人聊天dom

5.驗證客戶端的完整性socket

6.socket的阻塞模型與非阻塞模型tcp

 

 

開始今日份整理分佈式

1.UDP傳輸的特色以及實驗spa

UDP與TCP都是傳輸層中的重要傳輸協議,下面說一下UDP的特色

1.1 UDP傳輸特色

無鏈接的,面向數據包,不可靠的,快速的,不須要accept/connect 也沒有握手

1.2 基於UDP的多人聊天

#服務端
import socket

sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1',8500))

while True:
    msg,addr = sk.recvfrom(1024)
    print(msg.decode())
    send_message = input('>>>').strip()
    sk.sendto(send_message.encode(),(addr))

sk.close()
#客戶端
import socket

sk = socket.socket(type= socket.SOCK_DGRAM)
while True:
    msg = input('>>>').strip()
    send_msg ='test1:'+ msg
    sk.sendto(send_msg.encode(),('127.0.0.1',8500))
    msg,addr =sk.recvfrom(1024)
    print(msg.decode())

sk.close()

多個

客戶端只要多拷貝幾份client代碼就能夠了,就會發如今服務器端出現不少用戶發過來的信息,因爲是在命令行界面,在input界面會阻塞,因此並不會立刻看到多人發來的信息。在圖形化界面就不會這樣了

2.UTP與UDP傳輸的區別

UTP的特性

  • 面向鏈接的 可靠的 全雙工的 流式傳輸
  • 面向鏈接 :同一時刻只能和一個客戶端通訊
  • 三次握手、四次揮手
  • 可靠的 :數據不丟失、慢
  • 全雙工 :可以雙向通訊
  • 流式傳輸 :粘包 無邊界

UDP的特性

  • 無鏈接的 面向數據包 不可靠的 快速的
  • 無鏈接的 :不須要accept/connect 也沒有握手
  • 面向數據包的 :不會粘包
  • 不可靠的 :沒有自動回覆的機制
  • 快速的 :沒有那些複雜的計算、保證數據傳輸的機制

咱們從上面看到,tcp爲何會黏包的緣由:本地端不知道發送端具體發送了多長的字符串,解決辦法就是自定義協議,規定在傳輸以前先要傳輸的大小先行發送過去。在對方來接收規定長度的文件。

3.基於tcp的low版帶驗證功能的FTP小程序

作實驗前謹記一個傳大文件須要先傳一個字典過去,讓對方知道

P5GZ(@DX2BOV{Q2YYE86U[5

3.1實驗一

目的:服務器以及客戶端互傳文件並動態校驗MD5

#服務端,比較low

import socket
import struct
import json
import hashlib
import os

sk = socket.socket()#網絡傳輸基本配置
sk.bind(('127.0.0.1',8500))#本地端口
sk.listen()
conn,addr = sk.accept()

def download(file_dic):#客戶端上傳
    print(3)
    while True:
        file_name = file_dic['file_name']#獲取文件名
        file_size = file_dic['file_size']#獲取文件大小
        ret = file_write(file_size,file_name)#收到的文件的MD5值
        print(ret)
        send_header(ret)#發送給客戶端,服務器端的MD5值
        print(addr,'接收成功!')
        break

def upload(file_dic):#客戶端下載
    while True:
        isfile_dict = {}
        file_name = file_dic['file_name']
        if os.path.isfile(file_name):
            isfile_dict['flag'] =1
            send_header(isfile_dict)
            send_file_dic ={}
            send_file_dic['file_name'] = file_name
            send_file_dic['file_size'] = os.path.getsize(file_name)
            print(send_file_dic)
            send_header(send_file_dic)     #發送頭文件
            ret =file_read(file_name)#傳輸具體的文件獲取MD5值
            send_header(ret)  # 發送給客戶端,服務器端的MD5值
            print(addr,'發送成功!')
            break
        else:
            isfile_dict['flag'] = 0
            send_header(isfile_dict)
            break



def get_header(date):#獲取頭文件
    header_json = date.decode()
    header_dic = json.loads(header_json)
    return header_dic

def send_header(obj):#發送頭文件
    header_json = json.dumps(obj)  # 頭文件的變爲str類型
    header_bytes = header_json.encode()  # 頭文件變爲bytes類型
    header_len = struct.pack('i', len(header_bytes))  # 計算頭文件的長度
    conn.send(header_len)  # 發送頭文件的長度
    conn.send(header_bytes)  # 發送頭文件

def file_write(file_size,filename):#文件寫入,同時獲得寫入後的文件的MD5值
    recevive_num = 0
    has = hashlib.md5()
    with open(filename,'wb')as f2:
        while recevive_num< file_size:
            contact = conn.recv(1024)
            if contact:
                f2.write(contact)
                recevive_num += len(contact)
                has.update(contact)
            else:
                break
        return {'MD5':has.hexdigest()}


def file_read(filename):#文件讀取,同時獲得他的MD5值
    has = hashlib.md5()
    with open(filename,'rb')as f1:
        while True:
            contact = f1.read(1024)
            conn.send(contact)
            if contact:
                has.update(contact)
            else:
                break
        return {'MD5':has.hexdigest()}

def run():
    print(addr)
    while True:
        file_len = conn.recv(4)[0]
        file_bytes = conn.recv(file_len)
        file_dic =get_header(file_bytes)
        print(file_dic)
        if file_dic['operation']== 'download':
            upload(file_dic)
        elif file_dic['operation'] == 'upload':
            download(file_dic)


run()

#客戶端

import socket
import struct
import json
import hashlib
import os
import sys

header_dic ={}
menu=[
    ('上傳文件',),
    ('下載文件',)
]


def __upload():
    while True:
        file_get = input('請輸入你要上傳文件的絕對路徑>>>').strip()
        if os.path.isfile(file_get):
            file_name = os.path.basename(file_get)#獲取文件名
            header_dic['file_name']=file_name
            file_size = os.path.getsize(file_get)#獲取文件大小
            header_dic['file_size'] = file_size
            header_dic['operation'] = 'upload'
            send_header(header_dic)#發送文件的頭文件
            ret =file_read(file_get,file_size)#傳輸具體的文件獲取MD5值
            MD5_len= sk.recv(4)[0]
            MD5_bytes = sk.recv(MD5_len)
            MD5_dict = get_header(MD5_bytes)
            if ret['MD5'] == MD5_dict['MD5']:
                print('上傳成功!')
                break
            else:
                print('上傳失敗!')
                break
        else:
            print('你輸入的文件路徑不存在,請從新確認!')


def __download():
    while True:
        file_get = input('請輸入你要下載的文件的文件名>>>').strip()
        header_dic['file_name'] = file_get
        header_dic['operation'] = 'download'
        send_header(header_dic)#發送一個頭文件給服務器
        header_len = sk.recv(4)[0]#接收頭文件的長度
        header_bytes = sk.recv(header_len)#接收頭文件的bytes類型
        file_dic = get_header(header_bytes)#解包,得到頭文件
        if file_dic['flag'] == 0:
            print('你要下載的文件不存在,請從新選擇......')
        else:
            print('文件存在')
            recv_file_header =sk.recv(4)[0]
            recv_file_header_bytes = sk.recv(recv_file_header)
            recv_file_dict = get_header(recv_file_header_bytes)
            file_size = recv_file_dict['file_size']
            file_name = recv_file_dict['file_name']
            ret = file_write(file_size,file_name)
            MD5_len = sk.recv(4)[0]#得到MD5字典的長度
            MD5_bytes = sk.recv(MD5_len)
            MD5_dict = get_header(MD5_bytes)#獲取MD5字典的內容
            if ret['MD5'] == MD5_dict['MD5']:
                print('文件校驗成功!')
                break
            else:
                print('你接收的文件損壞,沒法匹配!')
                break


def send_header(obj):#發送頭文件
    header_json = json.dumps(obj)  # 頭文件的變爲str類型
    header_bytes = header_json.encode()  # 頭文件變爲bytes類型
    header_len = struct.pack('i', len(header_bytes))  # 計算頭文件的長度
    sk.send(header_len)  # 發送頭文件的長度
    sk.send(header_bytes)  # 發送頭文件


def get_header(date):#獲取頭文件
    header_json = date.decode()
    header_dic = json.loads(header_json)
    return header_dic


def file_read(filename,file_size):#文件讀取,同時獲得他的MD5值
    has = hashlib.md5()
    recevive_num = 0
    with open(filename,'rb')as f1:
        while True:
            contact = f1.read(1024)
            if contact:
                sk.send(contact)
                has.update(contact)
                float_rate = int(recevive_num / file_size)
                rate = round(float_rate * 100, 2)
                sys.stdout.write('\r已下載:\033[1;32m{0}%\033[0m'.format(rate))
            else:
                break
        return {'MD5':has.hexdigest()}


def file_write(file_size,filename):#文件寫入,同時獲得寫入後的文件的MD5值
    recevive_num = 0
    has = hashlib.md5()
    with open(filename,'wb')as f2:
        while recevive_num < file_size:
            contact = sk.recv(1024)
            if contact:
                f2.write(contact)
                recevive_num += len(contact)
                has.update(contact)
                float_rate = float(recevive_num / file_size)
                rate = round(float_rate * 100, 2)
                sys.stdout.write('\r已下載:\033[1;32m{}%\033[0m'.format(rate))

            else:
                break
        print(2)
        return {'MD5':has.hexdigest()}


if __name__ == '__main__':
    sk = socket.socket()  # 網絡傳輸基本配置
    sk.connect(('127.0.0.1', 8500))  # 遠端端口
    while True:
        for i,j in enumerate(menu,1):
            print(i,j[0])
        choice = int(input('請輸入你想要實現的功能>>>').strip())
        if choice == 1:
            __upload()
        elif choice == 2:
            __download()

4.基於socketserver的多人聊天

#服務端
import socketserver

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        conn = self.request
        while True:
            date = conn.recv(1024).decode()
            print(date)
            msg = input('>>>').encode()
            conn.send(msg)

server = socketserver.ThreadingTCPServer(('127.0.0.1',8500),Myserver)
server.serve_forever()
#客戶端
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',8500))
while True:
        msg ='one' + input('>>>').strip()
        sk.send(msg.encode())
        data = sk.recv(1024).decode()
        print(data)

sk.close()

5.驗證客戶端的完整性

若是你想在分佈式系統中實現一個簡單的客戶端連接認證功能,又不像SSL那麼複雜,那麼利用hmac+加鹽的方式來實現

#服務端
import os
import hmac
import socket

sk = socket.socket()
sk.bind(('127.0.0.1',8500))
sk.listen()

def auth(conn):
    secret_key = b'alexsb'
    rand_b = os.urandom(32)
    conn.send(rand_b)
    obj = hmac.new(secret_key, rand_b)
    res1 = obj.digest()
    res2 = conn.recv(1024)
    cmp_res = hmac.compare_digest(res1, res2)
    return cmp_res

conn,addr = sk.accept()

res = auth(conn)
if res :
    print('正常客戶端')
    conn.send(b'hello')
else:
    conn.close()
conn.close()
sk.listen()
#客戶端
import hmac
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',8500))

def auth(sk):
    secret_key = b'alexsb'
    rand_b =sk.recv(32)
    obj =  hmac.new(secret_key,rand_b)
    res2 = obj.digest()
    sk.send(res2)

auth(sk)
msg = sk.recv(1024)
print(msg)

sk.close()

6.socket的阻塞模型與非阻塞模型

只是涉及很淺顯的一點阻塞模型

# 阻塞模型
    # accept
    # recv
    # recvfrom

# 非阻塞
    # accept
    # recv
    # recvfrom

import socket

# sk = socket.socket()
# sk.setblocking(False)
# sk.bind(('127.0.0.1',9000))
# sk.listen()
# while True:
#     try:
#         sk.accept()
#     except BlockingIOError:
#         pass
相關文章
相關標籤/搜索