当尝试通过 .NET 将文件上传到运行 pure-ftpd 的 ftp 服务器(配置为 FTPS而不是SFTP,需要显式 FTP over TLS)时,会引发异常:
Unhandled exception. System.Net.WebException: The underlying connection was closed: The server committed a protocol violation
.
服务器日志似乎表明一切进展顺利,直到客户端在收到150 Accepted data connection
日志消息后停止通信。
客户端日志表明字节已写入流,但关闭流似乎会触发异常。
在 ftp 服务器上创建一个文件;但是,没有内容写入其中。
其他客户端(即 Filezilla)可以毫无问题地上传文件(使用相同的凭据,从同一网络/机器到同一服务器)。
我见过的其他类似问题建议更改请求的各种属性(EnableSsl
, UseBinary
, UsePassive
, KeepAlive
, Timeout
)。我尝试了这些属性的各种组合,但无济于事。
我不知道问题是什么。我倾向于认为这是客户端错误配置,因为其他语言/客户端可以毫无问题地连接到服务器。我不称自己为 C#/.NET 开发人员,因此我可能缺少一些明显的东西 - 感谢任何帮助。
using System;
using System.IO;
using System.Net;
using System.Text;
Uri target = new Uri("ftp://ftp.example.com:21/filenamehere");
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(target);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.EnableSsl = true;
request.Credentials = new NetworkCredential("myusername", "password");
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
request.Timeout = -1;
Stream fileStream = File.OpenRead(@"testfile.txt");
Stream ftpStream = request.GetRequestStream();
byte[] buffer = new byte[10240];
int read;
while ((read = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
ftpStream.Write(buffer, 0, read);
Console.WriteLine("Uploaded {0} bytes", fileStream.Position);
}
ftpStream.Close();
Console.WriteLine("done...");
客户端输出:
Uploaded 10240 bytes
Uploaded 20480 bytes
Uploaded 30720 bytes
Uploaded 40960 bytes
Uploaded 51200 bytes
Uploaded 61440 bytes
Uploaded 71680 bytes
Uploaded 81920 bytes
Uploaded 92160 bytes
Uploaded 92295 bytes
未处理的异常。System.Net.WebException:基础连接已关闭:服务器在 System.Net.CommandStream.InvokeRequestCallback(Object obj) 在 System.Net.CommandStream.Abort (例外 e)在 System.Net.FtpWebRequest.DataStreamClosed(CloseExState closeState) 在 System.Net.FtpDataStream.System.Net.ICloseEx.CloseEx(CloseExState closeState) 在 System.Net.FtpDataStream 的 System.Net.CommandStream.CheckContinuePipeline() .Dispose(Boolean disposing) at System.IO.Stream.Close() at Program.$(String[] args) in /Users/user/MyApp/Program.cs:line 27
服务器输出:
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (?@XX.XX.XX.XX) [DEBUG] Command [user] [myusername]
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (?@XX.XX.XX.XX) [DEBUG] 331 User myusername OK. Password required
Jan 6 23:46:06 machine1 ftp.info pure-ftpd: (?@XX.XX.XX.XX) [INFO] myusername is now logged in
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] 230 OK. Current restricted directory is /
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] Command [pbsz] [0]
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] 200 PBSZ=0
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] Command [prot] [P]
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] 200 Data protection level set to "private"
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] Command [opts] [utf8 on]
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] 500 Unknown command
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] Command [pwd] []
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] 257 "/" is your current location
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] Command [type] [I]
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] 200 TYPE is now 8-bit binary
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] Command [pasv] []
Jan 6 23:46:06 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] 227 Entering Passive Mode (YY,YY,YY,YY,YY,YY)
Jan 6 23:46:07 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] Command [stor] [filenamehere]
Jan 6 23:46:07 machine1 ftp.debug pure-ftpd: (myusername@XX.XX.XX.XX) [DEBUG] 150 Accepted data connection