TCP网络编程_socket_FTP

TCP网络编程_socket

直接干实例1:

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实现文件的上传,下载,查看功能

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类型,通常用于服务端序列化,客户端反序列化

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()用与保存序列化结果到文件,再称之为持久

load()用于从文件中取内容后坍塌反序列化

持久化:一切内存里的东西写入硬盘后就持久化,开机后能再次看到

TCP三次握手和四次挥手

TCP为什么三次分手

  1. 第一次握手 客户端向服务端发送一个请求包 当服务端收到这个请求包的时间可以确定服务端的收信功能 和客户端的发信功能
  2. 第二次握手 服务端向客户端发送一个确认包,并同时发送一个请求包, 客户端可以确认 自己可以收发信,服务端也可以收发信
  3. 第三次握手 客户端向服务端发送一个确认包 服务端可以确认 自己的发信功能和客户端的收信功能,结合第一次握手的信息已经确认双方收发信功能没有问题

TCP为什么要四次挥手

  1. 客户端发送一个分手包
  2. 服务端收到后立马确认
  3. 把手头剩余的事情做完后再次发送分手包给客户端
  4. 客户端收到后再次发送确认包等待2MSL时间后退出,服务端收到确认包后结束连接,如果在没有收到会再次发送分手包

什么是2MSL

MSL是客户端到服务端一次通信的最长时间,如果在这个时间内没有送达,认为丢包了

一来一回最长时间就是2MSL,所以任何一方在发出信息后,如果2MSL内没有收到回复,就认为丢包

通常在四次握手最后一次,客户端发出最后确认分手包后,服务端在收到这个包后会断开连接,无法再发送消息

所以客户端只有等待这么长时间,如果在这个时间段内没有再次收到新的分手包,就认为服务端已经下线,我也是可以离开

转载于:https://my.oschina.net/u/3978509/blog/2987968

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值