TCP網絡編程_socket_FTP

TCP網絡編程_socket

直接幹實例1:python

1V1 聊天程序(TCP)

需求: 使用TCP 顯示兩我的的1V1即時聊天服務編程

客戶端

# 實現利用TCP協議的1V1聊天程序
from socket import *


def V1():
    #  建立對象
    client_1 = socket(AF_INET, SOCK_STREAM)
    # 準備地址
    address = ('192.168.2.104', 7877)
    #  發送地址
    client_1.connect(address)
    while True:
        context = input('請留言:')
        if context == "exit":
            print('已結束聊天!')
            break
        try:
            client_1.send(context.encode('utf-8'))
        except:
            print('發送失敗!鏈接已中斷')
            break
        # 接收數據
        server_data = client_1.recv(1024)
        while True:
            if server_data:
                print(f'來自回覆:{server_data.decode("utf-8")}')
                break
            else:
                break


def main():
    V1()


if __name__ == '__main__':
    main()

服務端

# 實現利用TCP協議的1V1聊天程序
from socket import *


def V2():
    #  建立對象
    client_2 = socket(AF_INET, SOCK_STREAM)
    # 準備地址
    address = ('', 7877)
    #  發送地址
    client_2.bind(address)
    client_2.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    # 最大鏈接數
    client_2.listen(2)
    news_client, address_client = client_2.accept()
    while True:
        try:
            # 獲取內容
            raw_data = news_client.recv(1024).decode('utf-8')
        except:
            print('鏈接已中斷!')
            break
        if raw_data.split():
            print(f'來自: {address_client[0]} 留言:{raw_data}')
            context = input('回覆內容:')
            if context:
                news_client.send(context.encode('utf-8'))
            else:
                print('聊天已結束!')
                break
        else:
            print('聊天已結束!')
            break


def main():
    V2()


if __name__ == '__main__':
    main()

結果: 效果初步實現,但不足的是隻能一句一句的回覆,同時間只能有一方說話 ( 例: 對講機 )服務器

實例二網絡

自定義FTP協議功能

需求: 使用SOCKET實現文件的上傳,下載,查看功能socket

FTP客戶端

# 設定 L:讀   G: 下載     P: 上傳
from socket import *
import pickle


def upload(data):
    # 建立對象
    upload_client = socket(AF_INET, SOCK_STREAM)
    # 超時管理
    upload_client.settimeout(1)
    # 地址
    upload_address = ('172.16.17.197', 7788)  # 鏈接服務器
    try:
        upload_client.connect(upload_address)
    except:
        print('鏈接服務端失敗!')
    # 打開文件
    with open(f'{data[2:]}', 'rb') as f:
        # 讀取文件
        file_data = f.read(1024)
        # 發送文件頭
        upload_client.send((data + '|@_@|').encode('utf-8'))
        res = 0
        while file_data:
            # 發送指令
            res += upload_client.send(file_data)
            file_data = f.read(1024)
        upload_client.close()
    print(f'上傳{res} 個字節完成!')
    return True


def download(data):
    # 建立對象
    download_client = socket(AF_INET, SOCK_STREAM)
    # 超時管理
    download_client.settimeout(1)
    # 地址
    download_address = ('172.16.17.197', 7788)
    # 鏈接服務器
    try:
        download_client.connect(download_address)
        # 發送指令
        download_client.send(data.encode('utf-8'))
    except:
        print('鏈接服務端錯誤,發送失敗!')
    # 接收響應結果
    raw_data = download_client.recv(1024)
    # 打開文件
    with open(f'{data[2:]}_bak', 'wb') as f:
        # 寫入文件
        while raw_data:
            f.write(raw_data)
            # print(raw_data)
            raw_data = download_client.recv(1024)
        f.close()
    download_client.close()
    print('下載完成!')
    return True


def show(data):
    # 建立對象
    show_client = socket(AF_INET, SOCK_STREAM)
    # 地址
    show_address = ('172.16.17.197', 7788)
    # 超時管理
    show_client.settimeout(1)
    # 鏈接服務器
    try:
        show_client.connect(show_address)
        # 發送指令
        show_client.send(data.encode('utf-8'))
    except:
        print('鏈接服務端錯誤,發送失敗!')
    # 接收響應結果
    try:
        raw_data = show_client.recv(1024)
    except:
        print('服務端未響應')
    else:
        print('結果:', pickle.loads(raw_data))
    show_client.close()


def main():
    while True:
        inputData = input('輸入命令:').strip()  # 去除空格
        if inputData[0].upper() == "L":
            show(inputData)
        elif inputData[0].upper() == "G":
            return_res = download(inputData)
            if return_res:
                #  下載完成
                break
            else:
                print('下載失敗!')
                break
        elif inputData[0].upper() == "P":
            # 是否上傳完成
            res = upload(inputData)
            if res:
                # 上傳完成
                break
            else:
                print('上傳失敗!')
                break

        else:
            print('命令錯誤!')
            break


if __name__ == '__main__':
    main()

FTP服務端

import os
from socket import *
import pickle


# 查看
def show(news_socket):
    # 查詢當前目錄下文件
    files = os.listdir(os.getcwd())
    # dumps 序列化
    news_socket.send(pickle.dumps(files))
    # 關閉
    news_socket.close()


# 下載
def download(news_socket, raw_data):
    # 獲取文件名
    with open(f'{raw_data[2:]}', 'rb') as f:
        # 讀取文件
        file_data = f.read(1024)
        send_size = 0
        while file_data:
            # 發送字節碼
            send_size += news_socket.send(file_data)
            file_data = f.read(1024)
            print(f'已下載:{send_size} 個字節')
    news_socket.close()


def upload(file_data, news_socket):
    # 解出文件名
    file_name = file_data.split(b'|@_@|')[0]
    file_name = file_name.split(b':')[1]
    with open(file_name.decode('utf-8') + '_bak', 'ab') as f:
        # 接收數據
        files_data = file_data.split(b'|@_@|')[1]
        raw_data = news_socket.recv(1024)
        if files_data:
            f.write(files_data)
        while raw_data:
            # 寫入
            f.write(raw_data)
            raw_data = news_socket.recv(1024)
        news_socket.close()


def main():
    # 建立對象
    ftp_server = socket(AF_INET, SOCK_STREAM)
    # 綁定端口
    ftp_server.bind(('', 7788))
    # 同時最大鏈接數
    ftp_server.listen(5)

    while True:
        try:
            # 建立新
            news_socket, client_info = ftp_server.accept()
            # 獲取指令
            # 獲取原始數據 指令
            raw_data = news_socket.recv(1024)
            if raw_data[0:1].upper().decode('utf-8') == "L":
                # 查看
                show(news_socket)
            elif raw_data[0:1].upper().decode('utf-8') == "G":
                # 下載
                download(news_socket, raw_data.decode('utf-8'))
            elif raw_data[0:1].upper().decode('utf-8') == "P":
                upload(raw_data, news_socket)
            else:
                # 未檢測到內容輸入,退出操做
                ftp_server.close()
                break
        except:
            print('參數異常!')
            break


if __name__ == '__main__':
    main()

序列化與反序列化

經過pickle的dumps方法把任何數據轉化成能夠網絡上傳輸的bytes類型,一般用於服務端序列化,客戶端反序列化code

import pickle

var_a = {'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)}

# 序列化
>>> var_b = pickle.dumps(var_a)
>>> var_b
b'\x80\x03}q\x00(X\x01\x00\x00\x00eq\x01K\nX\x01\x00\x00\x00aq\x02X\x03\x00\x00\x00strq\x03X\x01\x00\x00\x00fq\x04]q\x05(K\x01K\x02K\x03eX\x01\x00\x00\x00gq\x06K\x04K\x05K\x06\x87q\x07X\x01\x00\x00\x00bq\x08G@&333333X\x01\x00\x00\x00cq\t\x88X\x01\x00\x00\x00dq\nNu.'

# 反序列化
>>> var_c = pickle.loads(var_b)
>>> var_c
{'e': 10, 'a': 'str', 'f': [1, 2, 3], 'g': (4, 5, 6), 'b': 11.1, 'c': True, 'd': None}

dump()用與保存序列化結果到文件,再稱之爲持久server

load()用於從文件中取內容後坍塌反序列化對象

持久化:一切內存裏的東西寫入硬盤後就持久化,開機後能再次看到ip

TCP三次握手和四次揮手

TCP爲何三次分手

  1. 第一次握手 客戶端向服務端發送一個請求包 當服務端收到這個請求包的時間能夠肯定服務端的收信功能 和客戶端的發信功能
  2. 第二次握手 服務端向客戶端發送一個確認包,並同時發送一個請求包, 客戶端能夠確認 本身能夠收發信,服務端也能夠收發信
  3. 第三次握手 客戶端向服務端發送一個確認包 服務端能夠確認 本身的發信功能和客戶端的收信功能,結合第一次握手的信息已經確認雙方收發信功能沒有問題

TCP爲何要四次揮手

  1. 客戶端發送一個分手包
  2. 服務端收到後立馬確認
  3. 把手頭剩餘的事情作完後再次發送分手包給客戶端
  4. 客戶端收到後再次發送確認包等待2MSL時間後退出,服務端收到確認包後結束鏈接,若是在沒有收到會再次發送分手包

什麼是2MSL

MSL是客戶端到服務端一次通訊的最長時間,若是在這個時間內沒有送達,認爲丟包了內存

一來一回最長時間就是2MSL,因此任何一方在發出信息後,若是2MSL內沒有收到回覆,就認爲丟包

一般在四次握手最後一次,客戶端發出最後確認分手包後,服務端在收到這個包後會斷開鏈接,沒法再發送消息

因此客戶端只有等待這麼長時間,若是在這個時間段內沒有再次收到新的分手包,就認爲服務端已經下線,我也是能夠離開

相關文章
相關標籤/搜索