网络编程(sock)搞定!

前些日子写了一个网络编程的,纯新手,能优化的地方很多!但是,也算自己独立完成了这么一个东西,晚上发上来!!

socket_project

项目结构:

│ readme
│ 原理图.png

├─.idea
│ │ misc.xml
│ │ modules.xml
│ │ workspace.xml
│ │ 网络编程.iml
│ │
│ └─inspectionProfiles
├─client
│ ├─bin
│ │ start.py
│ │
│ ├─conf_c
│ │ │ info_c.py
│ │ │
│ │ └─__pycache__
│ │ info_c.cpython-35.pyc
│ │
│ ├─core
│ │ │ main.py
│ │ │
│ │ └─__pycache__
│ │ main.cpython-35.pyc
│ │
│ └─file_position
└─server
├─bin
│ start.py

├─conf
│ │ info.py
│ │ __init__.py
│ │
│ └─__pycache__
│ info.cpython-35.pyc
│ __init__.cpython-35.py

├─core
│ │ main.py
│ │
│ └─__pycache__
│ main.cpython-35.pyc

├─file_position
│ │ 1.mp4
│ │
│ └─ncp
└─user_db
auth_file

README

功能:
用户加密认证
每个用户有自己的家目录,且只能访问自己的家目录
对用户进行磁盘配额,每个用户的可用空间不同
允许用户在ftp server上随意切换目录
允许用户查看当前目录下的文件
允许上传和下载文件,并保证文件的一致性
文件传输过程中显示进度条
附加:支持文件的断点续传
开发的程序需符合PEP8开发规范,及专业的生产软件设计规范,包括目录、代码命名、功能接口等

user_dic = {'ncp':'123123','cpp':'321321','tesla':'222222'}
测试用的两个文件,一个视频文件放在服务端的共享目录:file_position,测试文件在客户端的file_position的ncp下,一个文件小于20M一个大于
用户磁盘配额说明:total_package = {'ncp':count_size(20),'cpp':count_size(10),'tesla':count_size(50)}
ncp:20M   cpp:10M    tesla:50M

1.用户密码通过hash的md5算法加密
2.这里没有采用多线程或者多进程,后期可加
3.用户有自己的家目录,用ls查看自己家目录下的文件
4.用户可以用cd path完成路径切换,path为你要切换的目录(注意,如果cd后不加空格就输入会报错)
5.磁盘配完成
6.用户可以上传、下载并且包头用了md5随机加密,每次操作md5不一样
6.能显示进度条,client使用get下载文件时,并且可以断定续传,原理相同,没有在put上实现
7.自己强化的功能就是client可以使用大部分DOS命令对服务端进行操作
说明
#author:nie cheng ping
# _*_ coding=gbk _*_
from client.conf_c import info_c
import hashlib
import socket
import struct
import json
import os
import sys
import math
import time

class FTPclient:
    socket_net = info_c.socket_net
    socket_type = info_c.socket_type
    package_recv = info_c.package_size
    str_code = info_c.coding
    file_path = info_c.file_path_c

    def __init__(self,server_ip_port,connection=True):
        self.socket = socket.socket(self.socket_net,self.socket_type)
        self.server_ip_port = server_ip_port
        if connection:
            self.connection()
        else:
            self.close_line()

    def connection(self):
        self.socket.connect(self.server_ip_port)
        print(self.server_ip_port)

    def close_line(self):
        self.socket.close()

    def progress(self, recvd, total):
        fraction = '{:.0%}'.format(recvd / total)
        sys.stdout.write('
[%-30s] %s' % ('#' * int(math.floor(recvd * 30 / total)),fraction))
        sys.stdout.flush()
        if recvd == total:
            sys.stdout.write('
')

    def run_commands(self,inp):
        if not inp: return
        header = self.socket.recv(4)
        header_json_len = struct.unpack('i',header)[0]
        header_json = json.loads(self.socket.recv(header_json_len).decode(self.str_code))
        data_len = header_json['package_size']
        recv_data = b''
        recv_size = 0
        while recv_size < data_len:
            recv_data += self.socket.recv(self.package_recv)
            recv_size += self.package_recv
        print(recv_data.decode(self.str_code))
        return

    def get(self,user):
        header = self.socket.recv(4) # 接收报头长度
        print(header)
        header_json_len = struct.unpack('i',header)[0] # 根据报头长度拆分报头
        # 获取报头中的报头信息
        header_bytes = self.socket.recv(header_json_len)

        header_bytes_json = header_bytes.decode(self.str_code)
        # decode得到报文头内容,再反序列化
        header_json_dic = json.loads(header_bytes_json)
        print(header_json_dic)
        data_len = header_json_dic['file_size'] # data_len 等于总的数据长度
        share_file = os.path.join(self.file_path,user,header_json_dic['filename'])
        if os.path.exists(share_file):
            with open(share_file,'rb')as f:
                data = f.read()              # data 等于断后现有的数据大小
                if len(data) < data_len:
                    recv_size = 0
                    while recv_size < len(data):
                        recv_data = self.socket.recv(self.package_recv)
                        recv_size += len(recv_data)
                        self.progress(recv_size,len(data))
                with open(share_file,'ab+')as f:
                    f.seek(len(data))
                    recv_data = b''
                    recv_size = len(data)
                    while recv_size < data_len:
                        recv_data = self.socket.recv(self.package_recv)
                        recv_size += len(recv_data)
                        f.write(recv_data)
                        self.progress(recv_size,data_len)
                    return

        with open(share_file,'wb')as f:
            recv_size = 0
            while recv_size < data_len:
                recv_data = self.socket.recv(self.package_recv)
                f.write(recv_data)
                recv_size += len(recv_data)
                self.progress(recv_size,data_len)

    def put(self,inp,user,header):
        cmd = inp.split()
        share_file = os.path.join(self.file_path,user,cmd[1])
        send_size = 0
        with open(share_file,'rb')as f:
            for i in f:
                self.socket.send(i)
                send_size += len(i)
                self.progress(send_size,header['file_size'])
            else:
                print('send ok')

    def summary(self):
        while True:
            hash_data = hashlib.md5()

            data_user = self.socket.recv(self.package_recv)
            print(data_user.decode(self.str_code))
            inp_user = input('>>')
            self.socket.send(inp_user.encode(self.str_code))

            data_pass = self.socket.recv(self.package_recv)
            print(data_pass.decode(self.str_code))
            inp_password = input('>>')
            hash_data.update(inp_password.encode(self.str_code))
            self.socket.send(hash_data.hexdigest().encode(self.str_code))

            data_recv = self.socket.recv(self.package_recv)
            if data_recv.decode(self.str_code) == 'ok':
                user_file_dir = os.path.join(self.file_path,inp_user)

                if not os.path.exists(user_file_dir):
                    os.mkdir(user_file_dir)
                while True:
                    inp = input('>>')
                    if not inp: continue
                    cmd = inp.split()
                    while True:
                        if cmd[0] == 'get':
                            self.socket.send(inp.encode(self.str_code))
                            self.get(inp_user)
                        # 上次要设置用户在server端的磁盘大小空间,所以验证全在这里
                        elif cmd[0] == 'put':
                            share_file = os.path.join(self.file_path, inp_user, cmd[1])
                            if not os.path.exists(share_file):
                                print('file is not found')
                                break
                            self.socket.send(inp.encode(self.str_code))
                            header = {'filename': share_file,
                                      'file_size': os.path.getsize(share_file),
                                      'md5': info_c.hash_data.hexdigest()}
                            header_json = json.dumps(header)
                            header_json_bytes = header_json.encode(self.str_code)
                            header_struct = struct.pack('i', len(header_json_bytes))
                            self.socket.send(header_struct)
                            self.socket.send(header_json_bytes)
                            data = self.socket.recv(self.package_recv)
                            if data.decode(self.str_code) == 'ok':
                                self.put(inp,inp_user,header)
                            else:
                                print(data.decode(self.str_code))
                                break
                        else:
                            self.socket.send(inp.encode(self.str_code))
                            self.run_commands(inp)
                        break
            if data_recv.decode(self.str_code) == 'authentication is false':
                print(data_recv.decode(self.str_code))
                continue
#author:nie cheng ping
# _*_ coding=gbk _*_
import os
import socket
import hashlib
import json
import random
import string

ftp_path = 'file_position'
user_db_file = 'user_db'
auth_name = 'auth_file'
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
user_db_path = os.path.join(base_dir,user_db_file)
auth_file = os.path.join(user_db_path,auth_name)
ftp_s_home = os.path.join(base_dir,ftp_path)
package_size = 4096
socket_net = socket.AF_INET
socket_type = socket.SOCK_STREAM
listen_line = 5
coding = 'gbk'

md5_data = ''.join(random.sample(string.digits,6))
hash_data = hashlib.md5()
hash_data.update(md5_data.encode(coding))


def count_size(number):
    number_bytes = number*1024*1024
    return number_bytes
total_package = {'ncp':count_size(20),'cpp':count_size(10),'tesla':count_size(50)}


def create_auth():
    user_name = ('ncp','cpp','tesla')
    user_dic = {'ncp':'123123','cpp':'321321','tesla':'222222'}
    hash_data = hashlib.md5()
    hash_list = []
    for i in user_name:
        hash_data.update(user_dic[i].encode('gbk'))
        hash_list.append(hash_data.hexdigest())
    user_auth = {'ncp':hash_list[0],'cpp':hash_list[1],'tesla':hash_list[2]}
    print(user_auth)

    with open(auth_file,'w')as fw:
        fw.write(json.dumps(user_auth))
        fw.close()

def authentication(data):
    with open(auth_file,'r')as fr:
        user_info = json.loads(fr.read())
        fr.close()
    if data[0] in user_info and data[1] == user_info[data[0]]:
        print('authentication is successful')
        return True
    else:
        return False
server_conf info.py
#author:nie cheng ping
# _*_ coding=gbk _*_
import os
import struct
import json
import socket
from server.conf import info
from server.conf.info import authentication
import re

class FTPserver:
    ftps_file = info.ftp_s_home
    package_size_tra = info.package_size
    str_code = info.coding
    listen = info.listen_line
    socket_net = info.socket_net
    socket_type = info.socket_type


    def __init__(self,server_ip_port,bind_active=True):
        self.server = server_ip_port
        self.socket = socket.socket(self.socket_net,self.socket_type)
        if bind_active:
            self.bind()
            self.listen_line()
        else:
            self.close_line()

    def bind(self):
        self.socket.bind(self.server)
        self.server_ip_port = self.socket.getsockname()

    def listen_line(self):
        self.socket.listen(self.listen)

    def wait_line(self):
        return self.socket.accept()

    def close_line(self):
        self.socket.close()

    def run_commands(self,cmd,user,path,active=True):
        if active:
            def function_struct(obj):
                header = {'package_size': len(obj)}
                header_json = json.dumps(header)
                header_json_bytes = header_json.encode(self.str_code)
                self.conn.send(struct.pack('i', len(header_json_bytes)))
                self.conn.send(header_json_bytes)
                self.conn.send(obj.encode(self.str_code))
            try:
                path = path.split(' ',1)
                if cmd == 'ls':
                    user_file_path = os.path.join(self.ftps_file,user)
                    obj = os.listdir(user_file_path)
                    if obj == []:
                        obj = 'there is nothing'
                    obj = json.dumps(obj)
                    function_struct(obj)
                elif cmd == 'cd':
                    os.chdir(path[1])
                    obj = os.getcwd()
                    print(obj)
                    function_struct(obj)
                else:
                    obj = os.popen(cmd).read()
                    if not obj:
                        obj = 'commands is not defined'
                    function_struct(obj)
            except ConnectionResetError:
                print('接收或执行异常')

    def get(self,cmd,user):
            share_file = os.path.join(self.ftps_file, cmd[1])
            header = {'filename':cmd[1],
                      'file_size':os.path.getsize(share_file),
                      'md5':info.hash_data.hexdigest()}
            header_json = json.dumps(header)
            header_json_bytes = header_json.encode(self.str_code)
            header_struct = struct.pack('i',len(header_json_bytes))
            print(header_struct)
            self.conn.send(header_struct)
            self.conn.send(header_json_bytes)
            data_len = header['file_size']
            send_size = 0
            with open(share_file,'rb')as f:
                for i in f:
                    self.conn.send(i)
                    send_size += len(i)

    def put(self,cmd,user,head_dic):   #user为登录的用户名    cmd为操作命令list,[0]为操作,[1]为操作信息
        share_file = os.path.join(self.ftps_file,user,cmd[1])
        # header_struct = self.conn.recv(4)
        # header_len = struct.unpack('i',header_struct)[0]
        # header_json = self.conn.recv(header_len).decode(self.str_code)
        # header_dic = json.loads(header_json)
        recv_size = 0
        total_size = head_dic['file_size']
        with open(share_file, 'wb')as f:
            while recv_size < total_size:
                recv_data = self.conn.recv(self.package_size_tra)
                f.write(recv_data)
                recv_size += len(recv_data)
            else:
                print('receive file complete')
            return

    def summary(self):
        while True:
            print('wait line')
            self.conn,self.addr_ip = self.wait_line() # 这个位置后面的代码里添加线程池
            print(self.addr_ip)
            while True:
                self.conn.send('输入用户名:'.encode(self.str_code))
                user = self.conn.recv(self.package_size_tra)
                if not user:continue
                user = user.decode(self.str_code)
                self.conn.send('输入密码:'.encode(self.str_code))
                password = self.conn.recv(self.package_size_tra)
                if not password:continue
                password = password.decode(self.str_code)
                # 生成用户账号、密码
                user_pass = (user,password)
                flag = authentication(user_pass)
                # 认证信息是否成功
                if flag == False:
                    self.conn.send('authentication is false'.encode(self.str_code))
                    continue
                else:
                    self.conn.send('ok'.encode(self.str_code))
                    user_file_path = os.path.join(self.ftps_file,user)

                    if not os.path.exists(user_file_path):
                        os.mkdir(user_file_path)

                    while True:
                        data = self.conn.recv(self.package_size_tra)
                        if not data:continue
                        datas = data.decode(self.str_code)
                        cmd = datas.split()
                        if cmd[0] == 'get':
                            if not os.path.exists(os.path.join(self.ftps_file,cmd[1])):
                                continue
                            self.get(cmd,user)
                        elif cmd[0] == 'put':
                            header_struct = self.conn.recv(4)
                            header_len = struct.unpack('i', header_struct)[0]
                            header_json = self.conn.recv(header_len).decode(self.str_code)
                            header_dic = json.loads(header_json)
                            file_data_size = 0
                            if header_dic['file_size'] > info.total_package[user]:
                                self.conn.send('file is too bigger'.encode(self.str_code))
                                continue
                            if os.listdir(user_file_path) == []:
                                self.conn.send('ok'.encode(self.str_code))
                                self.put(cmd, user, header_dic)
                                continue
                            for i in os.listdir(user_file_path):
                                file_data_size += os.path.getsize(os.path.join(user_file_path,i))
                            if file_data_size < info.total_package[user]:
                                if info.total_package[user] - file_data_size > header_dic['file_size']:
                                    self.conn.send('ok'.encode(self.str_code))
                                    self.put(cmd,user,header_dic)
                                else:
                                    self.conn.send('file is too bigger'.encode(self.str_code))
                                continue
                        else:
                            self.run_commands(cmd[0],user,datas)
                        continue
server_core main.py
# author:nie cheng ping
from  client.core.main import FTPclient
from  client.conf_c import info_c
import sys
base_dir = info_c.base_dir
sys.path.insert(0,base_dir)


if __name__ == '__main__':
    ftp_client = FTPclient(('127.0.0.1',8081))
    ftp_client.summary()   # 汇总程序功能!测试通过后设置端口ip复用
client_bin start.py
#author:nie cheng ping
# _*_ coding=gbk _*_
import os
import socket
import string
import hashlib
import random

base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
user_file_dir = 'file_position'
coding = 'gbk'

md5_data = ''.join(random.sample(string.digits,6))
hash_data = hashlib.md5()
hash_data.update(md5_data.encode(coding))

file_path_c = os.path.join(base_dir,user_file_dir)
package_size = 2048
socket_net = socket.AF_INET
socket_type = socket.SOCK_STREAM

commands_list = ['run_commands','get','put']
client_conf_c info_c.py
#author:nie cheng ping
# _*_ coding=gbk _*_
import os
import socket
import string
import hashlib
import random

base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
user_file_dir = 'file_position'
coding = 'gbk'

md5_data = ''.join(random.sample(string.digits,6))
hash_data = hashlib.md5()
hash_data.update(md5_data.encode(coding))

file_path_c = os.path.join(base_dir,user_file_dir)
package_size = 2048
socket_net = socket.AF_INET
socket_type = socket.SOCK_STREAM

commands_list = ['run_commands','get','put']
client_core main.py

哎,没什么文采,就这么将就一下了,上班忙,慢慢改进吧。

原文地址:https://www.cnblogs.com/encp/p/8269484.html