文章目录

  • 第一章FTP协议
    • 1.1 Ftp协议简介
    • 1.2 FTP支持的文件类型
    • 1.3 FTP文件的数据结构
    • 1.4 文件的传输方式
    • 1.5 FTP工作原理
      • 1.5.1 启动FTP
      • 1.5.2 建立控制连接
      • 1.5.3 建立数据连接
      • 1.5.4 关闭FTP
    • 1.6 FTP命令
    • 1.7 FTP应答
      • 1.7.1 FTP 应答格式
      • 1.7.2 FTP应答作用
      • 1.7.3 FTP应答数字含义
    • 1.8 FTP两种工作模式
      • 1.8.1 主动模式
      • 1.8.2 被动模式
      • 1.8.3 NAT或防火墙对主被动模式的影响
        • 1.8.3.1 什么是NAT
        • 1.8.3.2 FTP客户端处于NAT或防火墙之后的主动模式
        • 1.8.3.3 FTP客户端处于NAT或防火墙之后的被动模式
        • 1.8.3.4 FTP服务器处于NAT或防火墙之后的被动模式
  • 第二章 项目需求
    • 2.1 FTP命令列表
    • 2.2 参数配置
    • 2.3 空闲断开
    • 2.4 限速
    • 2.5 连接数限制
    • 2.6 断点续传
  • 第三章 系统设计
    • 3.1 系统逻辑结构
    • 3.2 字符串工具封装模块
    • 3.3参数配置模块设计
    • 3.4 FTP 命令映射实现
    • 3.5 内部进程间通信模块设计
    • 3.6断点续载与断点续传
      • 3.6.1断点续载
      • 3.6.2断点续传
    • 3.7限速实现
    • 3.8 空闲断开实现
      • 3.8.1 控制连接空闲断开
    • 3.8.2 数据连接空闲断开
    • 3.9 ABOR实现
    • 3.10 哈希表设计
    • 3.11 连接数限制
      • 3.11.1 最大连接数限制
      • 3.11.2 每IP连接数限制

内容会有少许删除,但是面试重点有提到,字体加粗的请注意,尤其hash设计那块。
后序代码和文章整理好会压缩上传。

第一章FTP协议

1.1 Ftp协议简介

文件传输协议FTP(File Transfer Protocol ,由 RFC959描述)。
FTP工作在TCP/IP协议的应用层,其传输层使用的是TCP协议,基于C/S模式工作

1.2 FTP支持的文件类型

ASCII码文件, 这是FTP默认的文本格式
EBCDIC码文件,它也是一种文本类型文件,用8位代码表示一个字符,该文本文件在传输时要求两端都使用EBCDIC码(文本文件)
图像文件,也称二进制文件类型,发送的数据为连续的比特流,通常用于传输二进制文件(二进制文件就是常见的乱码文件)
【二进制文件和ASCII码文件区别?】
【二进制文件和文本文件在物理上没有差别:由一系列的比特位组成的。差别在于逻辑上不同的解析方式。
以ASCII码进行传输会将 Windows中的\r \n Linux中为\n
以二进制方式传输文件,那么不做任何解析。】

本地文件,字节的大小由本地主机定义,也就是说每一个字节的比特数据由发送方规定

1.3 FTP文件的数据结构

文件结构,这是FTP默认的方式,文件被认为是一个连续的字节流,文件内部没有表示结构的信息
记录结构,该结构只适用于文本文件(ASCII码或EBCDIC码文件),记录结构文件是由连续的记录构成的
页结构,在FTP中,文件的一个部分被称为页,当文件是由非连续的多个部分组成时,使用页结构,这种文件成为随机访问文件,每页都带有页号发送,以便收方能随机地存储各页

1.4 文件的传输方式

流方式,这是支持文件传输的默认方式,文件以字节流形式传输
块方式,文件以一系列块来传输,每块前面都带有自己的头部,头部包含描述子代码域(8位)和计数域(16位),描述子代码域定义数据块的结束标志等内容,计数域说明了
数据块的字节数
压缩方式,用来对连续出现的相同字节进行压缩,现在已经很少使用

1.5 FTP工作原理

1.5.1 启动FTP

在客户端,通过交互的用户界面,客户从终端输入启动FTP的用户交互式命令

1.5.2 建立控制连接

客户端TCP协议层根据用户命令给出的服务器IP地址,向服务器提供FTP服务的21端口(该端口是TCP协议层用来传输FTP命令的端口)发出主动建立连接的请求,服务器收到请求后,通过3次握手,就在进行FTP命令处理的用户协议解释器进程和服务器协议解释器进程之间建立一条TCP连接

1.5.3 建立数据连接

当客户通过交互式的用户界面,向FTP服务器发出要下载服务器上某一文件的命令时,该命令被送到用户协议解释器

1.5.4 关闭FTP

当客户发出退出FTP的交互式命令时,控制连接被关闭,FTP服务结束

1.6 FTP命令

命令 功能说明
访问控制命令
USER 服务器上的用户名
PASS 用户口令
CWD或XCWD 改变工作目录
CDUP或XCUP 回到上一层目录
QUIT 退出
ACCT
SMNT
REIN
传输参数命令
PORT 数据端口,主要向服务器发送客户数据连接端口,格式为PORT h1,h2,h3,h4,p1,p2,其中32位的ip地址用h1,h2,h3,h4表示,16位的TCP端口号用p1,p2表示
PASV 此命令要求服务器数据传输进程在随机端口上监听,进入被动接收请求的状态
TYPE 文件类型,可指定ASCII码,二进制等
STRU 文件结构
MODE 传输模式
服务命令
STOR 保存文件,向服务器传输文件,如果文件已存在,原文件将被覆盖,如果文件不存在,则新建文件
APPE 与STOR功能类似,但如果文件在指定路径已存在,则把数据附加到原文件尾部,如果不存在,则新建文件
LIST 列出目录详细清单
NLIST 列出名字列表
REST 重新开始,参数代表服务器要重新开始的那一点,它并不传送文件,而是略过指定点前的数据,此命令后应该跟其他要求文件传输的FTP命令
ABOR 异常终止,此命令通知服务器终止以前的FTP命令和与之相关的数据传输,如果先前的操作已完成,则没有动作,返回226,如果没有没有完成,返回225
PWD或XPWD 打印当前目录
MKD或XMKD 新建目录
RMD或XRMD 删除目录
DELE 删除文件
RNFR,RNTO 重命名
SITE CHMOD 修改权限
SYST 获取系统信息
FEAT 服务器特性
SIZE 获得文件大小
STAT 返回服务器状态
NOOP 该命令不指定任何动作,只是要求服务器返回OK响应
HELP 帮助
STOU 暂不实现
ALLO 暂不实现

1.7 FTP应答

1.7.1 FTP 应答格式

服务器通过控制连接发送给客户端的FTP应答,由ASCII码形式的3位数字和一行文本提示信息组成,它们之间用一个空格分隔
应答信息的每行文本以回车和换行对结尾,如果需要产生一条多行的应答,第一行在3位数字应答代码之后包含一个连字符“-”,而不是空格符,最后一行包含相同的3位数字应答码,后跟一个空格符

1.7.2 FTP应答作用

确保在文件传输过程中的请求和正在执行的动作保持一致
保证用户程序总是可以得到服务器的状态信息,用户可以根据收到的状态信息对服务器是否正常执行了有关操作进行判定

1.7.3 FTP应答数字含义

第一位数字标识了响应是好,是坏或者未完成

应答 说明
1yz 预备状态
2yz 完成状态
3yz 中间状态
4yz 暂时拒绝状态
5yz 永久拒绝状态

第二位数相应大概是发生了什么错误(比如,文件系统错误,语法错误等)

应答 说明
x0z 语法 –这种响应指出了有语法错误
x1z 信息 –对于请求信息的响应,比如对状态或帮助的请求
x2z 连接 –关于控制连接和数据连接的响应
x3z 身份验证和账户 –对登录过程和账户处理的响应
x4z 为使用
x5z 文件系统 –请求传输时服务器文件系统的状态或其他文件系统动作状态

第三位为第二位数字更详细的说明
如:
|–|--|

500 Syntax error, command unrecognized(语法错误,命令不能被识别)
501 (参数语法错误)
502 (命令没有实现)
503 (命令顺序错误)
504 (没有实现这个命令参数)

1.74 ftp应答示例

#define FTP_DATACONN 150
#define FTP_NOOPOK 200
#define FTP_TYPEOK 200
#define FTP_PORTOK 200
#define FTP_EPRTOK 200
#define FTP_UMASKOK 200
#define FTP_CHMODOK 200
#define FTP_EPSVALLOK 200
#define FTP_STRUOK 200
#define FTP_MODEOK 200
#define FTP_PBSZOK 200
#define FTP_PROTOK 200
#define FTP_OPTSOK 200
#define FTP_ALLOOK 202
#define FTP_FEAT 211
#define FTP_STATOK 211
#define FTP_SIZEOK 213
#define FTP_MDTMOK 213
#define FTP_STATFILE_OK 213
#define FTP_SITEHELP 214
#define FTP_HELP 214
#define FTP_SYSTOK 215
#define FTP_GREET 220
#define FTP_GOODBYE 221
#define FTP_ABOR_NOCONN 225
#define FTP_TRANSFEROK 226
#define FTP_ABOROK 226
#define FTP_PASVOK 227
#define FTP_EPSVOK 229
#define FTP_LOGINOK 230
#define FTP_AUTHOK 234
#define FTP_CWDOK 250
#define FTP_RMDIROK 250
#define FTP_DELEOK 250
#define FTP_RENAMEOK 250
#define FTP_PWDOK 257
#define FTP_MKDIROK 257
#define FTP_GIVEPWORD 331
#define FTP_RESTOK 35
#define FTP_RNFROK 350
#define FTP_IDLE_TIMEOUT 421
#define FTP_DATA_TIMEOUT 421
#define FTP_TOO_MANY_USERS 421
#define FTP_IP_LIMIT 421
#define FTP_IP_DENY 421
#define FTP_TLS_FAIL 421
#define FTP_BADSENDCONN 425
#define FTP_BADSENDNET 426
#define FTP_BADSENDFILE 451
#define FTP_BADCMD 500
#define FTP_BADOPTS 501
#define FTP_COMMANDNOTIMPL 502
#define FTP_NEEDUSER 503
#define FTP_NEEDRNFR 503
#define FTP_BADPBSZ 503
#define FTP_BADPROT 503
#define FTP_BADSTRU 504
#define FTP_BADMODE 504
#define FTP_BADAUTH 504
#define FTP_NOSUCHPROT 504
#define FTP_NEEDENCRYPT 522
#define FTP_EPSVBAD 522
#define FTP_DATATLSBAD 522
#define FTP_LOGINERR 530
#define FTP_NOHANDLEPROT 536
#define FTP_FILEFAIL 550
#define FTP_NOPERM 550
#define FTP_UPLOADFAIL 553

1.8 FTP两种工作模式

1.8.1 主动模式


1、 客户端向服务器端发送PORT命令
客户端创建数据套接字
客户端绑定一个临时端口
客户端在套接字上监听
将IP与端口格式化为h1,h2,h3,h4,p1,p2
2、 服务器端以200响应
服务器端解析客户端发过来的IP与端口暂存起来,以便后续建立数据连接
3、 客户端向服务器端发送LIST
服务器端检测在收到LIST命令之前是否接收过PORT或PASV命令
如果没有接受过,则响应425Use PORT or PASV first
如果有接收过,并且是PORT,则服务器端创建数据套接字(bind 20端口),调用connect主动连接客户端IP与端口,从而建立数据连接
4、 服务器发送150应答给客户端,表示准备就绪,可以开始传输了
5、 开始传输列表
6、 服务器发送226应答给客户端,表示数据传输结束
传输结束,服务器端主动关闭数据套接字

1.8.2 被动模式



1、 客户端向服务器端发送PASV命令
2、 服务器端以227响应
服务器端创建监听套接字
服务器端绑定一个临时端口
服务器在套接字上监听
将IP与端口格式化为h1,h2,h3,h4,p1,p2响应给客户端,以便客户端发起数据连接
3、 客户端向服务器端发送LIST
服务器端检测在收到LIST命令之前是否接受过PORT或PASV命令
如果没有接收过,则响应424 Use PORT or PASV first
如果有接收过,并且是PASV,则调用accept被动接受客户端的连接,返回已连接套接字,从而建立数据连接
4、 服务器发送150应答给客户端,表示准备就绪,可以开始传输
5、 开始传输列表
6、 服务器发送226应答给客户端,表示数据传输结束
传输结束,客户端主动关闭数据套接字

1.8.3 NAT或防火墙对主被动模式的影响

1.8.3.1 什么是NAT

NAT的全称是(Network Address Transiation),通过NAT可以将内网私有IP地址转换为公网IP地址,一定程度上解决了公网地址不足的问题。

1.8.3.2 FTP客户端处于NAT或防火墙之后的主动模式


建立控制连接通道:
因为NAT会主动记录由内部发送外部的连接信息,而控制连接通道的建立是由客户端向服务器端连接的,因此这一条连接可以顺利建立起来。
客户端与服务器端数据连接建立时的通知
客户端先启用PORT BB端口,并通过命令通道告知FTP服务器,且等待服务器的主动连接

服务器主动连接客户端
由于通过NAT转换之后,服务器只能得知NAT的地址并不知道客户端的IP地址,因此FTP服务器会以20端口主动向NAT的PORT BB端口发送主动连接请求,但NAT并没有启用PORT BB端口,因而连接被拒绝。
【为什么PORT需要用20端口?(主动必须给NAT服务器专门配置映射规则)】
因为服务器并不是直接传输给客户端的,中间会先传送给NET服务器,然后经由NET服务器发送给客户端。假若服务器未绑定20端口,端口号是动态的,那么NET服务器就需要配置很多映射,不然连接会被拒。因此给客户端与NET服务器与FTP服务器的主动模式专门配置了一个20端口号。此外客户端可能还有防火墙会挡住,因此专门配置20端口号为连接通道。
总结FTP客户端处于NAT或防火墙之后,若主动(port)模式必须配置映射规则,否则不一定能连接成功。若被动(PASV)模式,客户端是可以经由NAT连接成功FTP服务器的。

1.8.3.3 FTP客户端处于NAT或防火墙之后的被动模式

1.8.3.4 FTP服务器处于NAT或防火墙之后的被动模式


(从内部向NAT服务器发送连接请求,NAT是可以自动维护的,但是从外部不一定可以,因此PORT BB 连接不到FTP服务器,除非加映射规则)

第二章 项目需求

2.1 FTP命令列表

2.2 参数配置

vi /etc/vsftpd/vsftpd.conf

2.3 空闲断开

2.4 限速

2.5 连接数限制

1-最大连接数限制
2-总连接数限制
3-同一个IP连接数限制

2.6 断点续传

第三章 系统设计

3.1 系统逻辑结构

【为什么使用多进程?】(父进程nobody进程,子进程FTP服务进程)
绝对不能使用多线程(多个线程共享同一工作目录,一个线程改变会影响其他线程)
IO复用也不可以,IO复用是用一个线程处理多客户端。
【为什么一个客户端连接服务器需要用两个进程?】
当一个客户端连接过来,普通用户是没有权限直接连接20端口,无法正常建立数据连接通道。nobody进程是协助服务进程创建数据连接通道,以及一些特殊权限的管理。


服务进程与nobody进程之间采用sockpair函数进行通信

3.2 字符串工具封装模块

3.3参数配置模块设计




3.4 FTP 命令映射实现

(具体后面会有上传文档和代码)

3.5 内部进程间通信模块设计

3.6断点续载与断点续传

3.6.1断点续载

【如何实现断点续载?】
在本项目中断点续载的实现仅仅实在是在客户端要求服务端断点续载的时候会给服务端发送一个定位。在代码中具体实现是用lseek() 函数来定位。然后就不从起始位置传输,,从定位的位置进行传输,这就实现了断点续载了。(三四行有效代码即可实现)

断点续传对应 REST+STOR命令,断点续载对应REST+RETR 命令。覆盖对应ATOR命令

3.6.2断点续传

https://blog.csdn.net/weixin_38055381/article/details/82753480?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
断点续传也可以采用APPE的方式进行续传。
不管是断点续传还是断点续载都是需要客户端来维护断点。
【数据下载阶段优化?】
在找的项目视频来做的,(用read函数和writen函数)它本身是用了多次的从用户态到内核态不断切换的拷贝,效率比较慢。之后进行优化是用了sendfile 函数来发送文件。该函数进行数据的读取和发送均在内核中完成,并且不用处理信号中断的情况。不涉及从用户空间到内核空间的切换,也不会将数据拷贝到用户空间的缓冲区中,因此效率比较高。
注:在未优化之前一个几十兆的文件得七八秒才能完成下载,优化之后一两秒就能完成下载。

3.7限速实现

限速的关键是睡眠,如果发现当前传输速度超过最大传输速度就让进程睡眠。
传输速度 = 传输字节数 / 传输时间;
如果 当前传输速度>最大传输速度 则
    睡眠时间 = (当前传输速度/最大传输速度-1)×当前传输时间

速度1/速度2 -1 = 时间2 / 时间1 -1 = (时间2-时间1) /时间1
(时间2 – 时间1) = (速度1 / 速度2 -1) * 时间1

3.8 空闲断开实现

3.8.1 控制连接空闲断开

首先是安装信号SIGALRM,并启动定时闹钟
如果在闹钟到来之前没有收到任何命令,则在SIGALRM信号处理程序中关闭控制连接,并给客户421Timeout的响应,并且退出会话。

3.8.2 数据连接空闲断开

如果当前处于数据传输的状态,那么即使控制连接通道空闲(在空闲时间内没有收到任何客户端的命令),也不应该退出会话。实现方法,只需要将先前设定的闹钟关闭即可
数据连接通道建立了,但是在一定的时间没有传输数据,那么应该将整个会话断开
在传输数据之前安装信号SIGALRM,并启动闹钟
在传输数据过程中,如果收到SIGALRM信号
如果sess->data_process = 0,则给客户端超时的响应421Data timeout. Reconnect Sorry, 并且退出会话。
如果sess->data_proces=1,将sess->data_process=0,重新安装信号SIGALRM,并启动闹钟。

3.9 ABOR实现

如果在进行数据传输,那么客户端向服务器发送的ABOR命令是通过紧急模式来传输的,否则是按照正常模式传输的。所以要处理ABOR命令,需要开启紧急模式接收数据。
服务器接收这个命令是可能处在两种状态:1、FTP服务命令已经完成,或者2、FTP服务命令还在执行中。
第一种情况:服务器关闭数据连接(如果数据连接是打开的)回应226代码,表示放弃命令已经成功处理
第二种情况,服务器放弃正在进行的FTP服务,关闭数据连接,放回426响应代码,表示请求服务请求异常终止,然后服务器发送226响应代码,表示放弃命令成功处理。

3.10 哈希表设计

散列表是在建立的时候,将数据项的关键码和数据项在表中的存储位置进行映射,从而实现在查找的时候,可不必进行关键码的比较即可直接访问相应的数据项的一种数据结构。
数据项所存储的表要用数组来实现。
给定关键码,经过散列函数计算得到的是关键码对应的数据项在数组中存储下标。
Hash table:缺点:表空间不易扩展, 优点:查找比较快
Hash map: 缺点:查找比较慢, 优点:表空间易扩展。

哈希表的概念:根据关键码而直接进行访问的数据结构。也就是说,它通过把关键码映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做哈希表。
哈希函数构造方法:
散列函数是一个压缩映像函数。关键码集合比散列表地址集合大得多。因此有可能经过散列函数的计算,把不同的关键码映射到同一个散列地址上,这就产生了冲突。即key1≠ key2,而hash(key1)=hash(key2),这种现象称冲突。
哈希函数选择的标准: 简单和均匀
简单指:计算简单快速,用时短。均匀指:哈希函数计算出来的地址能均匀分布在整个地址空间。
构造方法有:
直接定址法 数字分析法 平方取中法 折叠法 随机数法 除留余数法 乘余取整法
做本次项目之前对比了这几种方法性能,实验结果表明 链地址法与除留余数法配合性能最好,搜索关键码时所需对桶的平均访问次数最少。
冲突处理方法:
(哈希桶)链地址法(重点) 开地址法 建立公共溢出区
(1)链地址法:(本项目所用,并且其中的链表为双向链表,插入链表的头部)
基本思想:将所有哈希地址为i的元素构成一个称为同义词链的链表,并将链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。
通常,每个桶中的同义词子表都很短,设有N个关键码通过某有个散列函数,存放到散列表中的m个桶中。那么每一个桶中的同义词子表的平均长度为N/m。这样,以搜索平均长度为N/m的同义词子表代替了搜索长度为n的顺序表,搜索速度快得多。
应用链地址法处理移除,需要增设链接指针,似乎增加了存储开销。事实上,由于开地址法必须保持大量的空闲空间以确保搜索效率,如二次探查法要求装填因子α≤0.5,而表项所占空间又比指针大得多,所以使用连地址法反而比开地址法节省存储空间。
(2)开地址法:
思想:当关键码key的哈希地址Ho=hash(key)出现冲突时,以Ho为基础,擦汗恒另一个哈希地址H1,如果H1仍然冲突,再以Ho为基础产生另外一个哈希地址H2,……,直到找到一个不冲突的哈希地址Hi,将相应元素存入其中,这种方法有一个通用的再散列函数形式:
Hi=(Ho+di)%m, i=1,2,……,m-1;
其中Ho为hash(key),m为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。主要有以下四种:
线性探测再散列 二次探测再散列 伪随机探测再散列 双散列法

散列表性能分析:
由于冲突的存在,散列法在进行搜索的时候,实际上也要进行关键码的比较。
用平均搜索长度ASL衡量散列方法的搜索的性能。
根据搜素成功与否,它又有搜索成功的平均搜索长度ASLsucc和搜索不成功的平均搜索长度ASLunsucc之分。
搜索成功的平均搜索长度ASLsucc是指能搜索到待查表项的平均探查次数。它是找到表中各个已有表项的探查次数的平均值。
搜索不成功的平均搜索长度ASLunsucc是指在表中搜索不到待查的表项,但找到插入位置的平均探查次数。它是表中所有可能散列到的位置上要插入新元素时找到空桶的探查次数的平均值。。
哈希查找过程仍是一个给定值与关键字进行比较的过程。
评价哈希查找效率仍要用ASL
哈希发中影响关键字比较次数的因素有三个:
哈希函数、处理冲突的方法以及哈希表的装填因子。哈希表的装填因子α的定义如下:

α=哈希表中元素个数/哈希表的长度

散列表的装填因子α表明了表中的装满程度。越大,说明表越满,再插入新元素时发生冲突的可能性就越大。
当装填因子α较高时,选择的散列函数不同,散列表的搜索性能差别很大。在一般情况下多选用除留数法,其中的除数在使用上应选择不含有20以下的质因数的质数。
对散列表技术进行的实验评估表明,它具有很好的平均性能,优于一些传统的技术,如平均树。
但散列表在最坏情况下性能很不好。如果对一个有n个关键码的散列表执行一次搜索或插入操作,最坏情况下需要O(n)的时间。

3.11 连接数限制

最大连接数限制:设置一个变量计数连接数,然后与.conf文件设置的连接数对比

每IP连接数限制

3.11.1 最大连接数限制

将当前连接数保存于变量num_clients,然后与配置项tunable_max_clients进行比较,如果超过了就不让登录,当一个客户登录的时候,num_clients加1,当一个客户退出的时候,num_clients减1。

3.11.2 每IP连接数限制

维护两个哈希表
Static hash_t *s_ip_count_hash; :连接时候需要对ip数进行计数(维护ip和计数的对应关系)
Static hash_t *s_pid_ip_hash; :存储客户端的ip号。用来查找退出客户端对应的IP号。(维护进程和ip的对应关系)
将当前ip的连接数保存在变量nun_this_ip中,然后与配置项tunable_max_per_ip进行比较,如果超过了就不让登录,当一个客户登录的时候,要在s_ip_count_hash更新这个表中的对应表项,即该ip对应的连接数要加1,如果这个表象不存在,要在表中添加一条记录,并且将ip对应的连接数置1,当一个客户端退出的时候,那么该客户端对应ip的连接数要减1,处理过程是这样的,首先是客户端退出的时候,父进程需要知道这个客户端的ip,这可以通过在s_pid_ip_hash查找得到,得到了ip进而我们就可以在s_ip_count_hash表中找到对应的连接数,进而进行减1操作。

【项目】C++ MiniFtpd项目手册 笔记版相关推荐

  1. 中铁成本2.0系统服务器地址,中国中铁项目成本管理信息系统V2.0(电化版)操作手册.docx...

    中国中铁项目成本管理信息系统V2.0(电化版)操作手册 中国中铁工程项目成本管理信息系统V2.0(电化局专版)操作手册 PAGE \* MERGEFORMAT233 目录 TOC \o "1 ...

  2. 以太坊Dapp项目-网页钱包开发手册

    以太坊Dapp项目-网页钱包开发手册 修订日期 姓名 邮箱 2018-10-10 brucefeng brucefeng@brucefeng.com 前言 在之前的一篇文章以太坊智能合约项目-Toke ...

  3. 基于 Vue JS、Element UI、Nuxt JS的项目PC端前端手册

    基于 Vue JS.Element UI.Nuxt JS的项目PC端前端手册 前言:笔记写于2020年5月左右,刚开始做前端时整理的笔记 1.环境搭建 1.安装nodeJs ​ 官网下载地址:http ...

  4. python实战一个完整的项目-Python项目开发实战(第2版)高清晰PDF完整版+代码

    会写代码≠能做好项目! 1.建立有序生产环境 2.迅速融入开发团队 3.高效处理项目问题 网罗Python项目开发中的流程,让你的编程事半功倍 Python项目与封装/团队开发环境/问题驱动开发/源码 ...

  5. 《实战突击:PHP项目开发案例整合(第2版)(含DVD光盘1张)》

    <实战突击:PHP项目开发案例整合(第2版)(含DVD光盘1张)> 基本信息 作者: 徐康明    辛洪郁 出版社:电子工业出版社 ISBN:9787121221378 上架时间:2014 ...

  6. vue项目打包与配置-学习笔记

    文章目录 vue项目打包与配置-学习笔记 前端打包 打包的代码如何运行 打包指定不同的环境变量(开发,测试) 打包手动配置文件 打包压缩,大文件处理 gzip进一步压缩 打包app 打包部署模式 vu ...

  7. 实战突击:PHP项目开发案例整合(第2版)

    为什么80%的码农都做不了架构师?>>>    实战突击:PHP项目开发案例整合(第2版) 案例涉及行业广泛,实用性非常强.通过对<实战突击:PHP项目开发案例整合(第2版)& ...

  8. Python机器学习全流程项目实战精讲(2018版)

    Python机器学习全流程项目实战精讲(2018版) 网盘地址:https://pan.baidu.com/s/16SSVq74YC07M0dW1iDekPg 提取码: vu7r 备用地址(腾讯微云) ...

  9. Java从小白到大牛第4篇项目实战视频课程2——Java版QQ-关东升-专题视频课程

    Java从小白到大牛第4篇项目实战视频课程2--Java版QQ-1778人已学习 课程介绍         本项目是Java SE技术实现的QQ2006聊天工具,所涉及到的知识点:Java面向对象.L ...

最新文章

  1. 如何用cmd命令控制mysql数据库
  2. Java编程思想读书笔记--第21章并发
  3. SET QUOTED_IDENTIFIER ON
  4. 6、mysqldump备份数据库(附带实例)
  5. STL之bitset
  6. 指令 出厂_口碑营销_南澳出口木箱出厂价
  7. Latex+Texstudio+Texlive 2020 windows10 安装教程
  8. HDU - 4456 Crowd
  9. 面试准备——Java回顾:基础编程(基本语法、面向对象、异常处理)
  10. 唯一解的数独题目生成器——理解回溯法
  11. 计算机学院少女节条幅,女生节条幅大战又打响了!哪个高校条幅标语最撩人 网友酸了...
  12. 职称计算机 河南,2017年河南职称计算机报名入口
  13. MLP-Mixer简介和一些想法
  14. CentOS查找文件、文件夹、内容
  15. 入门-误差逆传播算法
  16. 了解计算机的配置及价格行情,最新电脑配置清单及价格的详细介绍
  17. 新年新气象,重新出发
  18. 010 极限的四则运算例题
  19. 关于git的commit提交回退的三种命令模式
  20. 医学分子生物学试题答案

热门文章

  1. Vue 项目报错 Extra semicolon semi 解决方法
  2. python 正则表达式解决包含且不包含某字符串的问题
  3. 【顾晨浩】龙头药房,支付配套政策落地
  4. excel如何批量完成手机号码实名认证?
  5. “王鹏你妹”相关域名被抢注
  6. shell脚本监控系统资源并通过短信报警
  7. Java IO(二)
  8. 凯聪网络摄像机SIP1201系列使用说明 说明书 设置教程
  9. 基于卷积神经网络的近红外夜间道路行人识别
  10. 高效编码时间管理插件 — wakatime