Linux基础篇——ftp的安装与配置

1. 为什么ftp

  安装ftp主要是还为了传输文件,但是我有一台服务器或者计算机,直接登录进去获取文件不行吗?为啥还要多此一举用ftp呢?原因是用ftp的话,它的会话是持久的,只有一次认证过程,传输多个文件都是使用同一个连接。因为 ftp 就是为远程文件交互而设计的,更适;而且有些时候只是为了单纯让你做一个文件传输,运维未必会给你一台服务器,这个时候往往只是给你搭建ftp服务。

2. 什么是ftp

  FTP(File Transfer Protocol,文件传输协议)TCP/IP协议组中的协议之一。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。在开发网站的时候,通常利用FTP协议把网页或程序传到Web服务器上。此外,由于FTP传输效率非常高,在网络上传输大的文件时,一般也采用该协议。

  默认情况下FTP协议使用TCP端口中的 20和21这两个端口,其中20用于传输数据,21用于传输控制信息。但是,是否使用20作为传输数据的端口与FTP使用的传输模式有关,如果采用主动模式,那么数据传输端口就是20;如果采用被动模式,则具体最终使用哪个端口要服务器端和客户端协商决定。

3. ftp的安装与配置

3.1 ftp的安装

  ftp的安装一般用yum直接在线安装;

# 直接yum在线安装
[root@node1 ~]# yum install -y vsftpd
已加载插件:fastestmirror, langpacks
Determining fastest mirrors
 * base: ftp.sjtu.edu.cn
 * extras: ftp.sjtu.edu.cn
 * updates: mirrors.ustc.edu.cn
base                                                                                                                                                                                    | 3.6 kB  00:00:00
extras                                                                                                                                                                                  | 2.9 kB  00:00:00
updates                                                                                                                                                                                 | 2.9 kB  00:00:00
updates/7/x86_64/primary_db                                                                                                                                                             |  14 MB  00:00:02
正在解决依赖关系
--> 正在检查事务
---> 软件包 vsftpd.x86_64.0.3.0.2-29.el7_9 将被 安装
--> 解决依赖关系完成

依赖关系解决

===============================================================================================================================================================================================================
 Package                                        架构                                           版本                                                      源                                               大小
===============================================================================================================================================================================================================
正在安装:
 vsftpd                                         x86_64                                         3.0.2-29.el7_9                                            updates                                         173 k

事务概要
===============================================================================================================================================================================================================
安装  1 软件包

总下载量:173 k
安装大小:353 k
Downloading packages:
警告:/var/cache/yum/x86_64/7/updates/packages/vsftpd-3.0.2-29.el7_9.x86_64.rpm: 头V3 RSA/SHA256 Signature, 密钥 ID f4a80eb5: NOKEY
vsftpd-3.0.2-29.el7_9.x86_64.rpm 的公钥尚未安装
vsftpd-3.0.2-29.el7_9.x86_64.rpm                                                                                                                                                        | 173 kB  00:00:00
从 file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 检索密钥
导入 GPG key 0xF4A80EB5:
 用户ID     : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
 指纹       : 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
 软件包     : centos-release-7-9.2009.0.el7.centos.x86_64 (@anaconda)
 来自       : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  正在安装    : vsftpd-3.0.2-29.el7_9.x86_64                                                                                                                                                               1/1
  验证中      : vsftpd-3.0.2-29.el7_9.x86_64                                                                                                                                                               1/1

已安装:
  vsftpd.x86_64 0:3.0.2-29.el7_9

完毕!


# 查看ftp状态
[root@node1 ~]# systemctl status vsftpd.service
● vsftpd.service - Vsftpd ftp daemon
   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
   Active: inactive (dead)

# 启动ftp
[root@node1 ~]# systemctl start vsftpd.service

# 查看下ftp的默认端口21,发现能正常启动
[root@node1 etc]# ss -anp | grep 21
u_str  LISTEN     0      5      /var/run/lsm/ipc/simc 20233                 * 0                   users:(("lsmd",pid=621,fd=4))
raw    UNCONN     0      0      [::]:58                 [::]:*                   users:(("NetworkManager",pid=733,fd=21))
tcp    LISTEN     0      32     [::]:21                 [::]:*                   users:(("vsftpd",pid=7543,fd=4))


# 因为还没配置好,先关闭ftp 
[root@node1 ~]# systemctl start vsftpd.service

3.2 ftp的配置文件/etc/vsftpd/vsftpd.conf

  ftp安装好后,配置文件在/etc/vsftpd/vsftpd.conf,利用vim ,修改配置文件。

#打开配置文件
vim /etc/vsftpd/vsftpd.conf

#显示行号
:set nu

#修改配置 12 行 不允许匿名访问(不登录默认访问某目录/var/ftp),要用户名和密码
anonymous_enable=NO


#修改配置83行  允许ascii文件上传
ascii_upload_enable=YES

#修改配置84行 允许ascii文件下载
ascii_download_enable=YES

#修改配置87行 
ftpd_banner=Welcome to blah FTP service.

#修改配置101,102,104行 将用户限制在为其配置的主目录
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list

#添加下列内容到vsftpd.conf末尾
use_localtime=YES

# 监听端口
listen_port=21

idle_session_timeout=300

# 设置启用虚拟用户功能
guest_enable=YES

# 制定宿主用户名(我们后续需要为我们的系统增加该用户)
guest_username=ftpuser

# 制定虚拟用户配置文件放置文件夹(需要我们自己建立)
user_config_dir=/etc/vsftpd/vuser_conf

# 允许写
allow_writeable_chroot=YES

data_connection_timeout=1
virtual_use_local_privs=YES
pasv_min_port=40000
pasv_max_port=40010
accept_timeout=5
connect_timeout=1

# wq!保存

3.3 ftp的账号、组、目录配置

# 新建一个ftpuser组
groupadd ftpuser

# 新建一个ftpuser账号,并且该账号不需要登录服务器,设定家目录在 /home/vsftpd
useradd -g ftpuser -M -d /home/vsftpd -s /sbin/nologin ftpuser

# 设置用户 ftpuser 的密码
passwd ftpuser

# 把 /home/vsftpd 的所有权给ftpuser.root
chown -R ftpuser:ftpuser  /home/vsftpd

# 在家目录下先创建两个文件夹,作为后续ftp账号的默认目录
mkdir -p  /home/vsftpd/ftp-user1 /home/vsftpd/ftp-user2

# 设置目录权限为755
chmod 755 -R /home/vsftpd

3.4 ftp的登录用户和密码设置

# 进入/etc/vsftpd/目录
cd /etc/vsftpd/

# 创建用户密码信息文件
vim vuser_passwd

#编辑如下内容,创建虚拟账户信息,奇数行为用户名,偶数行为密码
ftp-user1
123456
ftp-user2
123456
# wq!保存退出

# 生成虚拟用户数据文件
db_load -T -t hash -f /etc/vsftpd/vuser_passwd /etc/vsftpd/vuser_passwd.db

# 将该目录的权限改成600
chmod 600 /etc/vsftpd/vuser_passwd.db

3.5 编辑pam认证文件


# 查看系统位数
getconf LONG_BIT

# 备份pam认证文件
mv  /etc/pam.d/vsftpd  /etc/pam.d/vsftpd.bak

# 新建pam认证文件
vim /etc/pam.d/vsftpd

# 根据自己的操作系统选2行,不要全部都填写哟
# 注:db=/etc/vsftpd/vuser_passwd 中的vuser_passwd 是你生成的虚拟用户的db文件,这里不要加扩展名。

# 系统为32位:

auth required pam_userdb.so db=/etc/vsftpd/vuser_passwd account

required pam_userdb.so db=/etc/vsftpd/vuser_passwd

 

# 系统为64位:

auth required /lib64/security/pam_userdb.so db=/etc/vsftpd/vuser_passwd

account required /lib64/security/pam_userdb.so db=/etc/vsftpd/vuser_passwd

# wq!保存内容

3.6 创建虚拟用户配置目录



#创建上述配置文件中配置的虚拟用户文件夹,一定要对应章节3.2配置文件的user_config_dir=/etc/vsftpd/vuser_conf
mkdir -p /etc/vsftpd/vuser_conf

#切换进入 /etc/vsftpd/vuser_conf
cd  /etc/vsftpd/vuser_conf

#创建虚拟用户配置文件,文件名称要与虚拟用户名称相同,这里我们配置两个虚拟用户就创建两个配置文件

touch ftp-user1 ftp-user2

#编辑ftp-user1
vim ftp-user1

#写入以下内容
local_root=/home/vsftpd/ftp-user1
write_enable=YES
anon_umask=022
anon_world_readable_only=NO
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
#wq! 保存退出


#编辑ftp-user2
vim ftp-user2

#写入以下内容
local_root=/home/vsftpd/ftp-use2
write_enable=YES
anon_umask=022
anon_world_readable_only=NO
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
# wq! 保存退出

3.7 创建chroot_list


# 进入目录/etc/vsftpd
cd /etc/vsftpd

#创建使当前配置的虚拟用户允许访问的文件列表
vim chroot_list

#写入虚拟用户名
ftp-user1
ftp-user2

# wq! 保存退出

3.8 防火墙,SELinux等配置

  简单粗暴型,如果允许的话,直接关闭防火墙和SELinux,

#打开SELINUX配置文件
vim /etc/selinux/config
#修改配置参数
#注释  
SELINUX=enforcing
#增加  
SELINUX=disabled
#wq!保存完,需要重启!

systemctl stop firewalld.service

  也可以针对性的关闭防火墙和SELinux对ftp的限制。





#  SELINUX不对vsftp不做任何限制
setsebool -P ftpd_full_access on

# 防火墙设置 IPtables 的设置方式:
vi /etc/sysconfig/iptables
#编辑iptables文件,添加如下内容,开启21端口
-A INPUT -m state --state NEW -m tcp -p tcp --dport 21 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 40000:40010 -j ACCEPT



#firewall 的设置方式,以下指令
firewall-cmd --zone=public --add-service=ftp --permanent
firewall-cmd --zone=public --add-port=21/tcp --permanent
firewall-cmd --zone=public --add-port=40000-40010/tcp --permanent 

3.9 查看ftp状态、重启、停止、设置开机启动



#启动
systemctl start vsftpd.service

#重启
systemctl restart vsftpd.service


#停止
systemctl stop vsftpd.service

#查看状态
systemctl status vsftpd.service

#设置开机启动
systemctl enable vsftpd.service

3.10 测试ftp连接

  重启ftp,查看下ftp的状态和端口是否正常启动;

# 查看ftp的状态,必须要是 active (running)
[root@node1 home]# systemctl status vsftpd.service
● vsftpd.service - Vsftpd ftp daemon
   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
   Active: active (running) since 日 2022-03-27 22:26:43 CST; 1h 13min ago
  Process: 10312 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
 Main PID: 10313 (vsftpd)
    Tasks: 3
   CGroup: /system.slice/vsftpd.service
           ├─10313 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
           ├─10387 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
           └─10389 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf

# 查看ftp的进程和端口,发现正在以PID=10313的进程,port=21在运行着
[root@node1 home]# netstat -anp | grep ftp
tcp6       0      0 :::21                   :::*                    LISTEN      10313/vsftpd
tcp6       0      0 192.168.78.130:21       192.168.78.1:62662      ESTABLISHED 10387/vsftpd
unix  2      [ ]         DGRAM                    111814   10313/vsftpd
unix  3      [ ]         STREAM     CONNECTED     111966   10389/vsftpd
unix  3      [ ]         STREAM     CONNECTED     111965   10387/vsftpd

  先在windows的命令行telnet下端口,指令为telnet 192.168.78.130 21,网络通的话会跳转返回220 Welcome to blah FTP service.
在这里插入图片描述

图3.10.1 测试ftp端口是否能联通

  先在window命令行测试下是否能正常访问ftp,输入指令ftp 192.168.78.130 ,然后输入章节3.4 ftp的登录用户和密码设置中的用户名ftp-user1和密码123456,直到弹出230 Login successful才算登录成功。
在这里插入图片描述

图3.10.2 测试ftp是否能访问

4. ftp的连接工具推荐

  时至今日ftp技术已经非常普及了,这里博主推荐一些比较好用的ftp图形界面话连接工具,以开源免费为主,由于ftp的连接工具使用都比较简单,基本都是新建会话,填入Ip,端口,用户名,密码,然后登录,就可以开行的托拉拽实现文件的上传下载了,这里就不细讲了,只做软件的简单介绍。

  • FileZilla (所有平台):FileZilla是一个免费开源的适合Windows、Mac和Linux的FTP客户端软件,因为其实免费跨平台和易用性,因此它是很多FTP用户的最初选择,FileZilla下载速度非常快,功能齐全,如果你是Windows用户,你甚至还能利用它搭建一个家庭FTP服务器。
    在这里插入图片描述

    图4.1 FileZilla预览

  • WinSCP(Windows平台):WinSCP是一个免费开源的FTP客户端,同时支持SFTP和SCP协议,WinSCP是快速轻量级的FTP客户端,还支持一些高级功能,例如远程文字编辑。当你打开一个FTP服务器上的纯文本文件,在保存文件的时候会透明的保存和上传到远程服务器。

在这里插入图片描述

图4.2 WinSCP 预览

  • Cyberduck (Mac OS X) :Cyberduck是一个基于Mac OS X的免费开源的FTP客户端工具,它支持快速查找、远程文本编辑等功能,Mac用户如果对FileZilla不满意,但又不想花钱的话,可以尝试一个这个。

在这里插入图片描述

图4.3 Cyberduck预览

  • Xftp(windows):Xftp是一个功能强大的SFTP、FTP 文件收费传输软件。使用了 Xftp 以后,即支持ftp协议传输文件,也支持Windows 用户能安全地在 UNIX/Linux 和 Windows PC 之间传输文件,即服务器之间直接上传下载文件,功能强大,在windows下也有不少忠实粉丝。
    在这里插入图片描述
    图4.Xftp预览
用VS编写的FTP服务器软件,C#网络程序编程学习用。 代码: using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using System.Windows.Forms; namespace FtpServer { public partial class FtpServerForm : Form { TcpListener myTcpListener = null; private Thread listenThread; // 保存用户名和密码 Dictionary users; public FtpServerForm() { InitializeComponent(); // 初始化用户名和密码 users = new Dictionary(); users.Add("admin", "admin"); // 设置默认的主目录 tbxFtpRoot.Text = "F:/MyFtpServerRoot/"; IPAddress[] ips = Dns.GetHostAddresses(""); tbxFtpServerIp.Text = ips[5].ToString(); tbxFtpServerPort.Text = "21"; lstboxStatus.Enabled = false; } // 启动服务器 private void btnFtpServerStartStop_Click(object sender, EventArgs e) { if (myTcpListener == null) { listenThread = new Thread(ListenClientConnect); listenThread.IsBackground = true; listenThread.Start(); lstboxStatus.Enabled = true; lstboxStatus.Items.Clear(); lstboxStatus.Items.Add("已经启动Ftp服务..."); btnFtpServerStartStop.Text = "停止"; } else { myTcpListener.Stop(); myTcpListener = null; listenThread.Abort(); lstboxStatus.Items.Add("Ftp服务已停止!"); lstboxStatus.TopIndex = lstboxStatus.Items.Count - 1; btnFtpServerStartStop.Text = "启动"; } } // 监听端口,处理客户端连接 private void ListenClientConnect() { myTcpListener = new TcpListener(IPAddress.Parse(tbxFtpServerIp.Text), int.Parse(tbxFtpServerPort.Text)); // 开始监听传入的请求 myTcpListener.Start(); AddInfo("启动FTP服务成功!"); AddInfo("Ftp服务器运行中...[点击”停止“按钮停止FTP服务]"); while (true) { try { // 接收连接请求 TcpClient tcpClient = myTcpListener.AcceptTcpClient(); AddInfo(string.Format("客户端({0})与本机({1})建立Ftp连接", tcpClient.Client.RemoteEndPoint, myTcpListener.LocalEndpoint)); User user = new User(); user.commandSession = new UserSeesion(tcpClient); user.workDir = tbxFtpRoot.Text; Thread t = new Thread(UserProcessing); t.IsBackground = true; t.Start(user); } catch { break; } } } // 处理客户端用户请求 private void UserProcessing(object obj) { User user = (User)obj; string sendString = "220 FTP Server v1.0"; RepleyCommandToUser(user, sendString); while (true) { string receiveString = null; try { // 读取客户端发来的请求信息 receiveString = user.commandSession.streamReader.ReadLine(); } catch(Exception ex) { if (user.commandSession.tcpClient.Connected == false) { AddInfo(string.Format("客户端({0}断开连接!)", user.commandSession.tcpClient.Client.RemoteEndPoint)); } else { AddInfo("接收命令失败!" + ex.Message); } break; } if (receiveString == null) { AddInfo("接收字符串为null,结束线程!"); break; } AddInfo(string.Format("来自{0}:[{1}]", user.commandSession.tcpClient.Client.RemoteEndPoint, receiveString)); // 分解客户端发来的控制信息中的命令和参数 string command = receiveString; string param = string.Empty; int index = receiveString.IndexOf(' '); if (index != -1) { command = receiveString.Substring(0, index).ToUpper(); param = receiveString.Substring(command.Length).Trim(); } // 处理不需登录即可响应的命令(这里只处理QUIT) if (command == "QUIT") { // 关闭TCP连接并释放与其关联的所有资源 user.commandSession.Close(); return; } else { switch (user.loginOK) { // 等待用户输入用户名: case 0: CommandUser(user, command, param); break; // 等待用户输入密码 case 1: CommandPassword(user, command, param); break; // 用户名和密码验证正确后登陆 case 2: switch (command) { case "CWD": CommandCWD(user, param); break; case "PWD": CommandPWD(user); break; case "PASV": CommandPASV(user); break; case "PORT": CommandPORT(user, param); break; case "LIST": CommandLIST(user, param); break; case "NLIST": CommandLIST(user, param); break; // 处理下载文件命令 case "RETR": CommandRETR(user, param); break; // 处理上传文件命令 case "STOR": CommandSTOR(user, param); break; // 处理删除命令 case "DELE": CommandDELE(user, param); break; // 使用Type命令在ASCII和二进制模式进行变换 case "TYPE": CommandTYPE(user, param); break; default: sendString = "502 command is not implemented."; RepleyCommandToUser(user, sendString); break; } break; } } } } // 想客户端返回响应码 private void RepleyCommandToUser(User user, string str) { try { user.commandSession.streamWriter.WriteLine(str); AddInfo(string.Format("向客户端({0})发送[{1}]", user.commandSession.tcpClient.Client.RemoteEndPoint, str)); } catch { AddInfo(string.Format("向客户端({0})发送信息失败", user.commandSession.tcpClient.Client.RemoteEndPoint)); } } // 向屏幕输出显示状态信息(这里使用了委托机制) private delegate void AddInfoDelegate(string str); private void AddInfo(string str) { // 如果调用AddInfo()方法的线程与创建ListView控件的线程不在一个线程时 // 此时利用委托在创建ListView的线程上调用 if (lstboxStatus.InvokeRequired == true) { AddInfoDelegate d = new AddInfoDelegate(AddInfo); this.Invoke(d, str); } else { lstboxStatus.Items.Add(str); lstboxStatus.TopIndex = lstboxStatus.Items.Count - 1; lstboxStatus.ClearSelected(); } } #region 处理各个命令 #region 登录过程,即用户身份验证过程 // 处理USER命令,接收用户名但不进行验证 private void CommandUser(User user, string command, string param) { string sendString = string.Empty; if (command == "USER") { sendString = "331 USER command OK, password required."; user.userName = param; // 设置loginOk=1为了确保后面紧接的要求输入密码 // 1表示已接收到用户名,等到接收密码 user.loginOK = 1; } else { sendString = "501 USER command syntax error."; } RepleyCommandToUser(user, sendString); } // 处理PASS命令,验证用户名和密码 private void CommandPassword(User user, string command, string param) { string sendString = string.Empty; if (command == "PASS") { string password = null; if (users.TryGetValue(user.userName, out password)) { if (password == param) { sendString = "230 User logged in success"; // 2表示登录成功 user.loginOK = 2; } else { sendString = "530 Password incorrect."; } } else { sendString = "530 User name or password incorrect."; } } else { sendString = "501 PASS command Syntax error."; } RepleyCommandToUser(user, sendString); // 用户当前工作目录 user.currentDir = user.workDir; } #endregion #region 文件管理命令 // 处理CWD命令,改变工作目录 private void CommandCWD(User user, string temp) { string sendString = string.Empty; try { string dir = user.workDir.TrimEnd('/') + temp; // 是否为当前目录的子目录,且不包含父目录名称 if (Directory.Exists(dir)) { user.currentDir = dir; sendString = "250 Directory changed to '" + dir + "' successfully"; } else { sendString = "550 Directory '" + dir + "' does not exist"; } } catch { sendString = "502 Directory changed unsuccessfully"; } RepleyCommandToUser(user,sendString); } // 处理PWD命令,显示工作目录 private void CommandPWD(User user) { string sendString = string.Empty; sendString = "257 '" + user.currentDir + "' is the current directory"; RepleyCommandToUser(user, sendString); } // 处理LIST/NLIST命令,想客户端发送当前或指定目录下的所有文件名和子目录名 private void CommandLIST(User user, string parameter) { string sendString = string.Empty; DateTimeFormatInfo dateTimeFormat = new CultureInfo("en-US", true).DateTimeFormat; // 得到目录列表 string[] dir = Directory.GetDirectories(user.currentDir); if (string.IsNullOrEmpty(parameter) == false) { if (Directory.Exists(user.currentDir + parameter)) { dir = Directory.GetDirectories(user.currentDir + parameter); } else { string s = user.currentDir.TrimEnd('/'); user.currentDir = s.Substring(0, s.LastIndexOf("/") + 1); } } for (int i = 0; i < dir.Length; i++) { string folderName = Path.GetFileName(dir[i]); DirectoryInfo d = new DirectoryInfo(dir[i]); // 按下面的格式输出目录列表 sendString += @"dwr-\t" + Dns.GetHostName() + "\t" + dateTimeFormat.GetAbbreviatedMonthName(d.CreationTime.Month) + d.CreationTime.ToString(" dd yyyy") + "\t" + folderName + Environment.NewLine; } // 得到文件列表 string[] files = Directory.GetFiles(user.currentDir); if (string.IsNullOrEmpty(parameter) == false) { if (Directory.Exists(user.currentDir + parameter + "/")) { files = Directory.GetFiles(user.currentDir + parameter + "/"); } } for (int i = 0; i 1024的随机端口 // 下面这个运算算法只是为了得到一个大于1024的端口值 port = random1 << 8 | random2; try { user.dataListener = new TcpListener(localip, port); AddInfo("TCP 数据连接已打开(被动模式)--" + localip.ToString() + ":" + port); } catch { continue; } user.isPassive = true; string temp = localip.ToString().Replace('.', ','); // 必须把端口号IP地址告诉客户端,客户端接收到响应命令后, // 再通过新的端口连接服务器的端口P,然后进行文件数据传输 sendString = "227 Entering Passive Mode(" + temp + "," + random1 + "," + random2 + ")"; RepleyCommandToUser(user, sendString); user.dataListener.Start(); break; } } // 处理PORT命令,使用主动模式进行传输 private void CommandPORT(User user, string portstring) { // 主动模式时,客户端必须告知服务器接收数据的端口号,PORT 命令格式为:PORT address // address参数的格式为i1、i2、i3、i4、p1、p2,其中i1、i2、i3、i4表示IP地址 // 下面通过.字符串来组合这四个参数得到IP地址 // p1、p2表示端口号,下面通过int.Parse(temp[4]) << 8) | int.Parse(temp[5] // 这个算法来获得一个大于1024的端口来发送给服务器 string sendString = string.Empty; string[] temp = portstring.Split(','); string ipString = "" + temp[0] + "." + temp[1] + "." + temp[2] + "." + temp[3]; // 客户端发出PORT命令把客户端的IP地址和随机的端口告诉服务器 int portNum = (int.Parse(temp[4]) < 0) { user.dataSession.binaryWriter.Write(bytes, 0, count); user.dataSession.binaryWriter.Flush(); count = binaryReader.Read(bytes, 0, bytes.Length); } } else { StreamReader streamReader = new StreamReader(fs); while (streamReader.Peek() > -1) { user.dataSession.streamWriter.WriteLine(streamReader.ReadLine()); } } AddInfo("...]发送完毕!"); } finally { user.dataSession.Close(); fs.Close(); } } // 使用数据连接接收文件流(客户端发送上传文件功能) private void ReadFileByUserSession(User user, FileStream fs) { AddInfo("接收用户上传数据(文件流):[..."); try { if (user.isBinary) { byte[] bytes = new byte[1024]; BinaryWriter binaryWriter = new BinaryWriter(fs); int count = user.dataSession.binaryReader.Read(bytes, 0, bytes.Length); while (count > 0) { binaryWriter.Write(bytes, 0, count); binaryWriter.Flush(); count = user.dataSession.binaryReader.Read(bytes, 0, bytes.Length); } } else { StreamWriter streamWriter = new StreamWriter(fs); while (user.dataSession.streamReader.Peek() > -1) { streamWriter.Write(user.dataSession.streamReader.ReadLine()); streamWriter.Flush(); } } AddInfo("...]接收完毕"); } finally { user.dataSession.Close(); fs.Close(); } } private void label3_Click(object sender, EventArgs e) { } } }
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

╭⌒若隐_RowYet——大数据

谢谢小哥哥,小姐姐的巨款

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值