网络基础

端口:

  拥有IP地址的主机可以提供许多服务.比如Web服务,FTP服务,SMTP服务这些服务完全通过1个IP地址来实现.那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务关系是一对多的关系.实际上是通过"IP地址+端口号"来区分不同的服务.

  端口是为了将同一台电脑上的不同程序进行隔离

  IP是找电脑,而端口是找电脑上的程序.

示例:

  MySQL是一个软件,软件帮助我们在硬盘上进行文件操作.默认端口:3306

  Redis是一个软件,软件帮助我们在内存里进行数据操作.默认端口:6379

  网站默认端口:80  ,访问时 :http://www.luffycity.com:80

  网站默认端口:443 ,访问时:https://www.luffycity.com:443

端口范围:

  1~65535   但是1~1024是内置(默认)不可用

OSI 7层模型

  人们按照分工不同把互联网协议从逻辑上划分了层级:

  

应用层 : 使用软件     打开软件或网站
表示层 : 看到数据,图片,视频    生产数据:szwwd
会话层 : 保持链接状态或登录     应用偷偷携带一点其他数据:令牌19rRNAwf8GVe6xyT9kJPIu5SlQc

socket模块:
传输层 : TCP/UDP      [TCP][szwwd|19rRNAwf8GVe6xyT9kJPIu5SlQc]
网络层 : IP     【IP】【[TCP][szwwd|19rRNAwf8GVe6xyT9kJPIu5SlQc]】
数据链路层 : MAC        [MAC][【IP】【[TCP][szwwd|19rRNAwf8GVe6xyT9kJPIu5SlQc]】]
物理层 : 将数据转换成电信号发送
TCP是因特网中的传输城协议,使用三次握手协议链接.当主动发出SYN请求链接后,等待对方回答SYN+ACK[1],并最终对对方的SYN执行ACK确认.这种建立连接的方法可以防止产生错误的连接.

tcp三次握手过程:
客户端发送SYN(SEQ = x)报文给服务端,进入SYN_SEND状态
服务器端收到SYN报文,回应一个SYN(SEQ = y)ACK(ACK = x+1)报文,进入SYN_RECV状态.
客户端收到服务器端的SYN报文,回应一个ACK(ACK = y+1)报文,进入Established状态.
三次握手完成,TCP客户端和服务端成功建立连接,可以开始数据传输.
TCP三次握手
建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由TCP的半关闭(half-close)造成的。
(1) 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。
(2) 接收到这个FIN的对端执行 “被动关闭”(passive close),这个FIN由TCP确认。
注意:FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。
(3) 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。
(4) 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。[1] 
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。
注意:
(1) “通常”是指,某些情况下,步骤1的FIN随数据一起发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。[2] 
(2) 在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close)。
(3) 当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN。
无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议,例如,HTTP/1.0却由服务器执行主动关闭。[2] 
TCP四次挥手

FTP进度条

#模拟进度条原理
import time

def func(size,total_size):
    val = int(size/total_size*100)
    time.sleep(0.02)
    print("
%s%%|%s"%(val,"*"*val),end="")
    
for i in range(101)
    func(i,100)
#os模块
import os
size = os.stat(r'D:sylars15day311.进度条.py').st_size
print(size)
计算文件大小

文件上传

import os
import json
import socketserver
import shutil

CODE = {'1001':'上传文件,从头开始上传'}

def upload(cmd_dict,conn,username):
    """
    服务端完成上传文件(含断点续传)
    :param cmd_dict:
    :param conn:
    :return:
    """
    #2.获取文件信息
    file_md5 = cmd_dict['md5']
    file_name = cmd_dict['file_name']

    file_path_path = os.path.join('home',username,file_md5)
    file_name_path = os.path.join('home',username,file_name)
    
    #判断文件是否存在
    exist = os.path.exists(file_md5_path)
    if not exist:  #不续传
    #3.1.1 可以开始上传了
        response = {'code':1001}
        conn.sendall(json.dumps(response).encode('utf-8'))

    #3.1.2接收上传文件内容
        f = open(file_md5_path,'wb')
        recv_size = 0
        while recv_size < upload_file_size:
            data = conn.recv(1024)
            f.write(data)
            f.flush()
            recv_size+=len(data)
        f.close()
    #3.1.3改名字
        shutil.move(file_md5_path,file_name_path)
    else: #续传
        #3.2 续传+大小
        exist_size = os.stat(file_md5_path).st_size
        response = {'code':1002,'size':exist_size}
        conn.sendall(json.dumps(response).encode('utf-8'))

        f = open(file_md5_path,'ab')
        recv_size = reist_size
        while recv_size < upload_file_size:
            data = conn.recv(1024)
            f.write()
            f.fiush()
            recv_size += len(data)
        f.close()

        #3.2.1改名字
        shutil.move(file_md5_path,file_name_path)

class NbServer(sockeretserver.BaseRequestHandler):
    def handle(self):
        """
        self.request 是客户端的socket对象
        :return:
        """
        #1.接收命令
        upload_cmd_bytes = self.request.recv(8096)
        cmd_dict = json.loads(upload_cmd_bytes.decode('utf8'))

        if cmd_dict['cmd'] == 'upload':
            upload(cmd_dict,self.request,'wj')
        elif cmd_dict['cmd'] == 'download':   #下载
            pass

if __name__ =='__main__':
    server = socketserver,ThreadingTCPServer(('127.0.0.1',8001),NbServer)
    server.serve_forever()
server
import os
import socket
import json
import hashlib

CODE = {'1001':'上传文件,从头开始上传'}

def file_md5(file_path):
    """
    文件进行md5加密
    :param file_path:
    :return:
    """
    obj = open(file_path,'rb')
    m = hashlib.md5()
    for line in obj:
        m.update(line)
    obj.close()
    return m.hexdigest()

def jdt(size,total_size):
    """
    显示进度条
    :return:
    """
    val = int(size/total_size*100)
    print('
%s%%|%s'%(val,"*"*val),end='')

def send_file(exist_size,file_total_size):
    """
    发送文件
    :param exist_size:开始读取字节的位置
    :param file_total_size: 文件总字节大小
    :return:
    """
    f = open(file_path,'rb')
    f.seek(exist_size)
    send_size = exist_size
    while send_size < file_total_size:
        data = f.read(1024)
        sk.sendall(data)
        send_size += len(data)
        jdt(send_size,file_total_size)
    f.close()
    print("上传成功")

def upload(file_path):
    """
    文件上传(含断点)
    :param file_path:
    :return:
    """
    file_md5_val = file_md5(file_path)
    file_name = os.path.basename(filee_path)
    file_size = os.stst(file_path).st_size

    cmd_dict = {'cmd':'upload','file_name':file_name,'size':file_size,'md5':file_md5_val}
    upload_cmd_bytes = json.dumps(cmd_dict).encode('utf-8')
    sk.sendall(upload_cmd_bytes)

    #2.等待服务端的响应
    response = json.loads(sk.recv(8096).decode('utf-8'))
    if response['code'] == 1001:
        send_file(0,file_size)
    else:
        #断点续传
        exist_size = response['size']
        send_file(exist_size,file_size)

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

while True:
    #upload|文件路径
    user_input = input("请输入要执行的命令:")
    #1.自定义协议{'cmd':'upload','file_path':'....'}
    cmd,file_path = user_input.split('|',maxsplit = 1)
    if cmd == 'upload':
        upload(file_path)
    elif cmd == 'download':
        pass
client

  

原文地址:https://www.cnblogs.com/wangjun187197/p/9606686.html