gpt4 book ai didi

C# FTP 服务器在处理 EPRT 命令后从不接收传入的传输连接

转载 作者:行者123 更新时间:2023-11-30 17:43:34 30 4
gpt4 key购买 nike

我正在构建一个 FTP 服务器,它将从相机获取图像并将照片存储在本地目录中。我在从给我的端口获取文件时遇到问题。这是对话:

Server(me):"220 Ready!"
Client:"USER Guest"
Server: "331 Username ok, need password"
Client:"PASS "
Server: "230 user logged in"
Client: "PWD"
Server: "257 \"/\""
Client: "EPRT |1|172.22.22.103|58719|
Server:"500 IDK"
Client: "PORT 172,22,22,103,147,237"
Server:"200 Ready for Transport"
Client: "TYPE I"
Server:"200 I understand it is an image file"
Client: "STOR .TEST.RHPRYI"

我通过将最后两个数字转换为十六进制 (93,ED) 并附加它们然后再转换回十进制来找到端口。我的最终端口是 37869。然后我创建了一个新的 TcpClient 用作下载,但我的 TcpListener 从未拿起相机。另外我不确定我的下载方法是否正确。

我从这里得到了很多代码:
http://www.codeproject.com/Articles/380769/Creating-an-FTP-Server-in-Csharp-with-IPv-Support

我的问题实际上归结为:如何在 C# 中将客户端发送的文件作为 FTP 服务器?

这是我的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Drawing;
using Microsoft.VisualBasic;
//Creates a TcpServer that is used to transfer images from the Axis Camera to a directory on a computer
//ftpdmin was chosen as the name because it was supposed to be a replica of a program in c just made in csharp
//However, it was really hard to transfer from c because all of the struct names and functions were nonintuitive
//This program is completely made from internet sources, and there are definitely bugs. For instance it does not implement
// many FTP calls.


namespace ftpdmin
{
class Server
{
//TCPListener listens to a given IP and port to wait for a connection with the camera

//Download Listener listens to the port given by the camera in the PORT command, which is the
//port at which the files needed to be downloaded are stored.

//Listen thread implements tcpListener. We do not want to be stuck in an infinite loop, but
//we always want to be listening to the camera. That is why we use another thread.

//Downlaod thread implements the downloadlistener for the same reason as above

//File name is the download files name given by the camera in the STOR command.

//direct is the directory to save the files at on the local computer. It was given in the main
// method of the console program. See Program.cs

private TcpListener tcpListener;
private TcpListener downloadListener;
private Thread listenThread;
private Thread downloadThread;
private string fileName;

private string direct;

//Initialize Ip adress and threads
public Server(string dir)
{
direct = dir;
this.tcpListener = new TcpListener(IPAddress.Parse("172.22.22.104"), 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}

private void ListenForClients()
{
//Start listening
this.tcpListener.Start();

while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();

//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}

private void ListenForDownloads()
{
this.downloadThread.Start();

while(true)
{
TcpClient downloadClient = this.downloadListener.AcceptTcpClient();
Thread clientDownloadThread = new Thread(new ParameterizedThreadStart(HandleClientDownload));
clientDownloadThread.Start(downloadClient);
}
}

private void HandleClientDownload(object downloadClient)
{
Console.WriteLine("IM HERE");
TcpClient downloaderClient = (TcpClient) downloadClient;
NetworkStream downloadStream = downloaderClient.GetStream();
StreamWriter downloadWriter = new StreamWriter(downloadStream, Encoding.ASCII);
StreamReader downloadReader = new StreamReader(downloadStream);
try
{
//Sets up the path to store the file
string path = Path.Combine(direct, fileName);
FileStream file = File.Create(path);
//Implements the method to download a file
CopyStream(file, downloadStream);
file.Close();
}
catch (Exception e)
{
Console.WriteLine("a socket error has occured:" + e);

}
}

private void HandleClientComm(object client)
{
//A Server is TCP has to respond to a bunch of commands from the client. The first thing it
//does when it connects is send code 220 which says it is good to continue.
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StreamWriter writer = new StreamWriter(clientStream, Encoding.ASCII);
StreamReader reader=new StreamReader(clientStream);
writer.WriteLine("220 Ready!");
writer.Flush();
string command=reader.ReadLine().ToUpperInvariant();
int downloadPort=0;
string ipOfDownload="";
Console.WriteLine(command);
while(!command.Equals("QUIT"))
{
//USER comes with the username given to the client. Here I do not check if the cameras username
//is the same as the username in the program. I just give the command 331 which means continue.
if(command.Contains("USER"))
{
writer.WriteLine("331 Username ok, need password");
writer.Flush();
}
//PASS is the same as username. I do not check the passwords, I just give 230 which continues the FTP.
else if(command.Contains("PASS"))
{
writer.WriteLine("230 User Logged In");
writer.Flush();
}
//PWD is Print working directory. I send 257 to say I have a PWD, and I send / because that is what is saved
// in the camera. I am not actually going to save files at this directory, I just want to continue.
else if(command.Contains("PWD"))
{
writer.WriteLine("257 \"/\"");
writer.Flush();
}
//This is an important command. The client is sending an IP where it wants to do file transfers. It comes in a
//Weird format so all this function is doing is allowing me store Ip as "172.22.22.103" instead of "PORT 172,22,22,103"
//Also there is a port listed at the end, but it is given in 2 numbers. The conversion to one port number is done by
//changing the two numbers to hexadecimal, appending them, and then transforming them back to decimal.
else if(command.Contains("PORT"))
{
string portPart1 = "";
string portPart2 = "";
Console.WriteLine(command);
int numberOfCommas=0;
int i=0;
bool notPort=true;
bool isNotPortPart2=true;
while(i<command.Length && notPort)
{
if(command[i].Equals(','))
{
if(numberOfCommas==3)
{
notPort=false;
}
else
{
ipOfDownload+=".";
numberOfCommas++;
}
}
else if(Information.IsNumeric(command[i]))
{
ipOfDownload+=command[i];
}
i++;
}
while(i<command.Length && isNotPortPart2)
{
if(Information.IsNumeric(command[i]))
{
portPart1+=command[i];
}
else
{
isNotPortPart2=false;
}
i++;
}
while(i<command.Length)
{
portPart2+=command[i];
i++;
}
Console.WriteLine("IP=" +ipOfDownload);
Console.WriteLine("PortPart1="+portPart1);
Console.WriteLine("PortPart2="+portPart2);
int portPart1int = int.Parse(portPart1);
int portPart2int = int.Parse(portPart2);
string portPart1Hex = portPart1int.ToString("X");
string portPart2Hex = portPart2int.ToString("X");
string downloadPortHex = portPart1Hex + portPart2Hex;
downloadPort = Convert.ToInt32(downloadPortHex, 16);
Console.WriteLine("PortPart1Hex=" + portPart1Hex);
Console.WriteLine("PortPart2Hex=" + portPart2Hex);
Console.WriteLine("FinalPort: " + downloadPort);
this.downloadListener = new TcpListener(IPAddress.Parse(ipOfDownload), downloadPort);
this.downloadThread = new Thread(new ThreadStart(ListenForDownloads));
writer.WriteLine("200 Ready for Transport");
writer.Flush();
}
//The client sends TYPE I for image. usually an ftp would switchto binary mode because that is the only way
//a file can be transferred cleanly.
else if(command.Contains("TYPE"))
{
writer.WriteLine("200 I understand it is an image file");
writer.Flush();
}
//This command gives the name of the file being transferred. I substring to get rid of
//The STOR . that comes before the file name
else if(command.Contains("STOR"))
{
fileName = command.Substring(6);
Console.WriteLine(fileName);
}
//For all other commands sent by the client, I send 500 which means I'm not implementing those commands.
else
{
writer.WriteLine("500 IDK");
writer.Flush();
}
command=reader.ReadLine().ToUpperInvariant();
Console.WriteLine(command);
}
writer.WriteLine("221 BYE");
writer.Flush();
tcpClient.Close();
}

private static long CopyStream(Stream input, Stream output, int bufferSize)
{
byte[] buffer = new byte[bufferSize];
int count = 0;
long total = 0;

while ((count = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, count);
total += count;
}

return total;
}

private static long CopyStreamAscii(Stream input, Stream output, int bufferSize)
{
char[] buffer = new char[bufferSize];
int count = 0;
long total = 0;

using (StreamReader rdr = new StreamReader(input))
{
using (StreamWriter wtr = new StreamWriter(output, Encoding.ASCII))
{
while ((count = rdr.Read(buffer, 0, buffer.Length)) > 0)
{
wtr.Write(buffer, 0, count);
total += count;
}
}
}

return total;
}

private long CopyStream(Stream input, Stream output)
{
//if (_transferType == "I")
//{
return CopyStream(input, output, 4096);
//}
//else
//{
// return CopyStreamAscii(input, output, 4096);
//}
}
}

最佳答案

通过 ERTP(或 PORT)命令,客户端告诉您的服务器客户端正在监听由服务器发起的传入传输连接。相反,您也开始倾听。所以双方都在倾听,什么也不会发生。

因此,您需要创建 TcpClient 并主动连接,而不是 TcpListener

参见 RFC 2428 .

您实现的类似于被动模式(EPSVPASV 命令),而客户端正在使用主动模式。


无论如何,您最好使用现有的 FTP 服务器实现,而不是尝试实现自己的。

关于C# FTP 服务器在处理 EPRT 命令后从不接收传入的传输连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30737246/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com