Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#FTP服务器在处理EPRT命令后从未收到传入的传输连接_C#_Ftp_Port - Fatal编程技术网

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

C#FTP服务器在处理EPRT命令后从未收到传入的传输连接,c#,ftp,port,C#,Ftp,Port,我正在构建一个FTP服务器,它将从相机获取图像并将照片存储在本地目录中。从提供给我的端口获取文件时遇到问题。以下是对话: 服务器(me):“220准备就绪!” 客户:“用户客户” 服务器:“331用户名确定,需要密码” 客户:“通过” 服务器:“230用户登录” 客户:“PWD” 服务器:“257\”/\” 客户:“EPRT | 1 | 172.22.22.103 | 58719 | 服务器:“500 IDK” 客户端:“端口172,22,22103147237” 服务器:“200准备好传输”

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

服务器(me):“220准备就绪!”
客户:“用户客户”
服务器:“331用户名确定,需要密码”
客户:“通过”
服务器:“230用户登录”
客户:“PWD”
服务器:“257\”/\”
客户:“EPRT | 1 | 172.22.22.103 | 58719 |
服务器:“500 IDK”
客户端:“端口172,22,22103147237”
服务器:“200准备好传输”
客户:“I型”
服务器:“200我知道这是一个图像文件”
客户:“STOR.TEST.RHPRYI”

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

我从这里得到了很多代码:

实际上,我的问题归结为:如何在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);
        //}
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用System.IO;
Net系统;
使用系统线程;
使用System.Net.Sockets;
使用系统图;
使用Microsoft.VisualBasic;
//创建用于将图像从Axis摄像机传输到计算机上目录的TcpServer
//之所以选择ftpdmin作为名称,是因为它应该是刚刚在csharp中用c编写的程序的副本
//然而,从c语言传输确实很困难,因为所有的结构名和函数都是非直观的
//这个程序完全是从互联网资源中开发出来的,肯定有漏洞。例如,它没有实现
//许多FTP呼叫。
命名空间ftpdmin
{
类服务器
{
//TCPListener侦听给定的IP和端口,以等待与摄像头的连接
//下载侦听器侦听port命令中摄像机给定的端口,该端口是
//存储需要下载的文件的端口。
//侦听线程实现了tcpListener。我们不想陷入无限循环,但是
//我们总是想听到摄像机的声音,这就是为什么我们使用另一条线。
//Downlaod线程实现downloadlistener的原因与上述相同
//文件名是相机在STOR命令中给出的下载文件名。
//direct是在本地计算机上保存文件的目录
//控制台程序的方法。请参阅program.cs
私人TcpListener TcpListener;
私有TcpListener下载侦听器;
私有线程listenThread;
私有线程下载线程;
私有字符串文件名;
私有字符串直接;
//初始化Ip地址和线程
公共服务器(字符串目录)
{
直接=直接;
this.tcpListener=新的tcpListener(IPAddress.Parse(“172.22.22.104”),3000);
this.listenThread=新线程(新线程开始(ListenForClients));
this.listenThread.Start();
}
私有void listenforcients()
{
//开始听
这个.tcpListener.Start();
while(true)
{
//阻止,直到客户端连接到服务器
TcpClient client=this.tcpListener.AcceptTcpClient();
//创建一个线程来处理通信
//使用连接的客户端
Thread clientThread=新线程(新的参数化ThreadStart(HandleClientCommand));
clientThread.Start(客户端);
}
}
私有void ListenForDownloads()
{
这个.downloadThread.Start();
while(true)
{
TcpClient downloadClient=this.downloadListener.AcceptTcpClient();
Thread clientDownloadThread=新线程(新的参数化ThreadStart(HandleClientDownload));
clientDownloadThread.Start(downloadClient);
}
}
私有void HandleClientDownload(对象下载客户端)
{
Console.WriteLine(“我在这里”);
TcpClient downloaderClient=(TcpClient)downloadClient;
NetworkStream downloadStream=downloaderClient.GetStream();
StreamWriter downloadWriter=新的StreamWriter(downloadStream,Encoding.ASCII);
StreamReader downloadReader=新的StreamReader(downloadStream);
尝试
{
//设置存储文件的路径
字符串路径=path.Combine(直接,文件名);
FileStream file=file.Create(路径);
//实现下载文件的方法
CopyStream(文件、下载流);
file.Close();
}
捕获(例外e)
{
Console.WriteLine(“发生套接字错误:“+e”);
}
}
私有void HandleClientCommand(对象客户端)
{
//服务器是TCP必须响应来自客户端的一系列命令
//当它连接时发送代码220,表示可以继续。
TcpClient TcpClient=(TcpClient)客户端;
NetworkStream clientStream=tcpClient.GetStream();
StreamWriter writer=新的StreamWriter(clientStream,Encoding.ASCII);
StreamReader=新的StreamReader(clientStream);
WriteLine(“220准备就绪!”);
writer.Flush();
string命令=reader.ReadLine().toupper不变量();
int downloadPort=0;
字符串ipOfDownload=“”;
控制台写入线(命令);
而(!command.Equals(“QUIT”))
{
//用户带有给客户端的用户名。这里我不检查摄像机的用户名
//与程序中的用户名相同。我只给出命令331,表示继续。
if(command.Contains)