socket网络编程

表示编程这条路真得好难走,后悔大学没有读信息专业啊。

第七周的作业:

1. 用户登陆
2. 上传/下载文件
3. 不同用户家目录不同
4. 查看当前目录下文件

刚开始没有一点思路,上网查了很多资料,还自学了FTP。吐槽一句,讲师真是太不负责了,作业要求不详细,还没有思路。

要实现通信,需要7个层次:物理层,数据链路(mac地址),网络层(IP),传输层(有标准的数据类型, TCP/IP 三次握手四次断开, UDP),会话层(http,smtp),表示层,应用层。 传输过程中就需要做到的事情是接收和发送,在python中,这部分功能被封装在socket模块的socket类中。

要实现文件上传和下载,肯定是需要两个端口:一个是服务器端(server),另外一个是客户端(client)。大致的交互流程如下:

理清楚思路之后,就是开始写代码了。

server端的代码如下:

import socket
import os
import sys
sys.path.append('..')
from conf import setting
com_path = setting.DATABASE

def run():
    server = socket.socket()
    server.bind(('localhost',6969))
    server.listen()

    while True:
        print('等待客户端的连入')
        conn, addr = server.accept()
        print('收到来自%s,%s的请求'%(str(conn),str(addr)))
        data = conn.recv(1024).decode()
        server_path = '%s\%s\%s'%(com_path['path'],com_path['server'],data)
        print('当前目录下的文件有:')
        print(os.listdir(server_path))
        #检查服务器端是否已经有目录存在,要是没有的化,创建一个目录
        if os.path.isdir(server_path):
            print('该用户的目录已经存在')
        else:
            os.mkdir(server_path)
            print('成功在远程端创建%s的目录'%data)
        while True:
            try:
                data = conn.recv(1024)
                if len(data) == 0:
                    continue
                else:
                    cmd, filename = data.decode().split()
                    file_path = "%s\%s.txt"%(server_path,filename)
                    print(cmd,filename)
                if cmd == 'download':
                    print(file_path)
                    if os.path.isfile(file_path):
                        with open(file_path,'rb') as f:
                            file_size = os.stat(file_path).st_size
                            conn.send(bytes(str(file_size),encoding='utf-8'))
                            print('已经成功传送了文件大小%s'%str(file_size))
                            conn.recv(1024) #服务器端发送文件大小后,接受客户端的相应
                            for line in f:
                                conn.send(bytes(str(line),encoding='utf-8'))
                elif cmd == 'upload':
                    receive_file_size = conn.recv(1024).decode()
                    conn.send('准备好接收文件'.encode())
                    receive_size = 0
                    file_total_size = int(receive_file_size)
                    with open(file_path, 'wb') as f:
                        while receive_size < file_total_size:
                            data = conn.recv(1024)
                            receive_size += len(data)
                            f.write(data)
                        print('file recv done')
                        print(receive_size,file_total_size)
                print('更新后目录下的文件有:')
                print(os.listdir(server_path))
            except Exception:
                print('客户端链接断开')
                break

    server.close()

  

client端的代码如下:

import socket
import sys
sys.path.append('..')
import os
from conf import setting
com_path = setting.DATABASE
current_user = None

def auth(func):
    def wrapper(*args,**kwargs):
        global current_user
        username, pwd = input('请输入您的用户名,密码:').strip().split(',')
        user_info_path = '%s\%s.txt'%(com_path['path'],com_path['user_info'])
        exist_flag = False
        not_user = False
        with open(user_info_path,'r') as f:
            while not exist_flag:
                for line in f:
                    if line.startswith(username):
                        if line.strip().split('|')[1] == pwd:
                            print('登录成功')
                            current_user = username
                            func()
                            break
                            exist_flag = True
                            not_user = True
                        else:
                            print('密码错误')
            if not not_user:
                print('用户不存在')
    return wrapper

@auth
def run():
    client = socket.socket()
    client.connect(('localhost',6969))
    client_path = '%s\%s\%s'%(com_path['path'],com_path['client'],current_user)

    client.send(current_user.encode())#将用户名发送给服务器端,看看是否有这个客户的目录

    while True:
        inp = input(">>:").strip()
        if len(inp) == 0:
            continue
        try:
            cmd,filename = inp.split()
            file_path = "%s\%s.txt"%(client_path,filename)
        except:
            print('输入有误,请重新输入')
            continue
        try:
            if cmd == 'download':
                client.send(inp.encode())
                receive_file_size = client.recv(1024).decode()
                print('server file size',receive_file_size)
                client.send('准备好接收文件'.encode())
                if os.path.isdir(client_path):
                    print('该用户的目录已经存在')
                else:
                    os.mkdir(client_path)
                    print('成功在远程端创建%s的目录'%data)
                receive_size = 0
                file_total_size = int(receive_file_size)
                with open(file_path,'wb')as f:
                    data = client.recv(1024)
                    receive_size += len(data)
                    f.write(data)
                    print('file recv done')
                    print(receive_size,file_total_size)

            elif cmd == 'upload':
                # try:
                if os.path.isfile(file_path):
                    client.send(bytes(inp,encoding='utf-8'))
                    with open(file_path,'rb') as f:
                        file_size = os.stat(file_path).st_size
                        print(file_size)
                        client.send(bytes(str(file_size),encoding='utf-8'))
                        print('已经成功传送了文件大小%s'%str(file_size))
                        client.recv(1024)
                        for line in f:
                            client.send(bytes(str(line), encoding='utf-8'))
                # except Exception:
                #     print('只能上传文件')
        except Exception:
            break
        client.close()

run()

本来想在写一个自己的类,然后继承socket类的,但是无奈,老是出现‘OSError: [WinError 10022] 提供了一个无效的参数’错误,这个BUG我也修改不了。所以就放弃了运用面向对象的方法。希望学到以后能回过头来找出今天没有能力解决的原因吧。

原文地址:https://www.cnblogs.com/little-hunter/p/6417646.html