草庐IT

用 C 代码编写基于 TCP 的 FTP 服务

coder 2023-09-19 原文

我正在尝试为多线程服务器编写 TCP FTP 服务。我找到了这个教程 http://www.mario-konrad.ch/wiki/doku.php?id=programming:multithreading:tutorial-04这对理解TCP协议(protocol)的客户端多线程非常有帮助。事实上,这段代码创建了一个可以同时接受来自不同客户端的多个连接的服务器。

但是,我正在努力寻找如何在其上应用 ftp 服务。精确地说明如何向 FTP 服务器发送文件和从 FTP 服务器获取文件。

有什么帮助吗?

最佳答案

下面的代码是我去年为一篇网络论文所做的作业。希望对您有所帮助。

#include <windows.h>
#include <stdio.h> 
#include <string.h>
#include <stdlib.h>
#include <winsock.h>
#include <winsock2.h>

#define BUFFERSIZE 800
#define WSVERS MAKEWORD(2,0)

WSADATA wsadata;    
void    wy_fileName_collector(char  *_buffer, char  *_nameBuffer);
int main(int argc, char *argv[]) 
{
    //INITIALIZATION
    struct sockaddr_in localaddr,remoteaddr;
    struct sockaddr_in remoteaddr_act;

    SOCKET s,ns;
    SOCKET s_data_act=0;

    char send_buffer[BUFFERSIZE],receive_buffer[BUFFERSIZE];
    char fileName[40];


    int n,bytes,addrlen;
    memset(&localaddr,0,sizeof(localaddr));//clean up the structure
    memset(&localaddr,0,sizeof(remoteaddr));//clean up the structure

    //WSASTARTUP
    if (WSAStartup(WSVERS, &wsadata) != 0)
    {
        WSACleanup();
        printf("WSAStartup failed\n");
        exit(1);
    }

    //SOCKET
    s = socket(PF_INET, SOCK_STREAM, 0);
    if (s <0)
    {
        printf("socket failed\n");
    }
    localaddr.sin_family = AF_INET;
    if (argc == 2) localaddr.sin_port = htons((u_short)atoi(argv[1]));
    else localaddr.sin_port = htons(1234);//default listening port
    localaddr.sin_addr.s_addr = INADDR_ANY;//server address should be local

    //BIND
    if (bind(s,(struct sockaddr *)(&localaddr),sizeof(localaddr)) != 0)
    {
        printf("Bind failed!\n");
        exit(0);
    }

    //LISTEN
    listen(s,5);

    while (1)
    {
        addrlen = sizeof(remoteaddr);

        //NEW SOCKET newsocket = accept
        ns = accept(s,(struct sockaddr *)(&remoteaddr),&addrlen);
        if (ns <0 ) break;
        printf("accepted a connection from client IP %s port %d \n",inet_ntoa(remoteaddr.sin_addr),ntohs(localaddr.sin_port));

        //Respond with welcome message
        sprintf(send_buffer,"\n==220 Welcome to Alan's FTP site== \r\n\n");
        bytes = send(ns, send_buffer, strlen(send_buffer), 0);

        while (1)
        {
            n = 0;
            while (1)
            {
                //RECEIVE
                bytes = recv(ns, &receive_buffer[n], 1, 0);//receive byte by byte...

                //PROCESS REQUEST
                if ( bytes <= 0 ) break;
                if (receive_buffer[n] == '\n')
                { /*end on a LF*/
                    receive_buffer[n] = '\0';
                    break;
                }
                if (receive_buffer[n] != '\r') n++; /*ignore CRs*/
            }
            if ( bytes <= 0 ) break;

            printf("-->DEBUG: the message from client reads: '%s' \r\n", receive_buffer);

            /**
              * @brief  Exception handling
              */
            if(strncmp(receive_buffer,"USER",4)  && strncmp(receive_buffer,"PASS",4)    &&  strncmp(receive_buffer,"SYST",4)
                    &&strncmp(receive_buffer,"PORT",4)   && strncmp(receive_buffer,"STOR",4)    &&  strncmp(receive_buffer,"RETR",4)
                    &&strncmp(receive_buffer,"LIST",4)  &&  strncmp(receive_buffer,"NLST",4)    &&  strncmp(receive_buffer,"QUIT",4))
            {
                sprintf(send_buffer,"202 Command not implemented, superfluous at this site. \r\n");
                bytes = send(ns, send_buffer, strlen(send_buffer), 0);
            }


            if (strncmp(receive_buffer,"USER",4)==0)
            {
                printf("Logging in \n");
                sprintf(send_buffer,"331 Password required \r\n");
                bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                if (bytes < 0) break;
            }

            if (strncmp(receive_buffer,"PASS",4)==0)
            {
                printf("Typing password (anything will do... \n");
                sprintf(send_buffer,"230 Public login sucessful \r\n");
                bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                if (bytes < 0) break;
            }

            if (strncmp(receive_buffer,"SYST",4)==0)
            {
                system("ver > tmp.txt");

                FILE *fin=fopen("tmp.txt","r");//open tmp.txt file
                sprintf(send_buffer,"150 Transfering... \r\n");
                bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                char temp_buffer[80];
                while (!feof(fin))
                {
                    fgets(temp_buffer,78,fin);
                    sprintf(send_buffer,"%s",temp_buffer);
                    send(s_data_act, send_buffer, strlen(send_buffer), 0);
                }
                fclose(fin);
                sprintf(send_buffer,"226 File transfer completed... \r\n");
                bytes = send(ns, send_buffer, strlen(send_buffer), 0);

                if (bytes < 0) break;
            }

            //PORT
            if(strncmp(receive_buffer,"PORT",4)==0)
            {
                s_data_act = socket(AF_INET, SOCK_STREAM, 0);
                //local variables
                unsigned char act_port[2];
                int act_ip[4], port_dec;
                char ip_decimal[40];
                sscanf(receive_buffer, "PORT %d,%d,%d,%d,%d,%d",&act_ip[0],&act_ip[1],&act_ip[2],&act_ip[3],(int*)&act_port[0],(int*)&act_port[1]);
                remoteaddr_act.sin_family=AF_INET;//local_data_addr_act
                sprintf(ip_decimal, "%d.%d.%d.%d", act_ip[0], act_ip[1], act_ip[2],act_ip[3]);
                printf("IP is %s\n",ip_decimal);
                remoteaddr_act.sin_addr.s_addr=inet_addr(ip_decimal);
                port_dec=act_port[0]*256+act_port[1];
                printf("port %d\n",port_dec);
                remoteaddr_act.sin_port=htons(port_dec);

                if (connect(s_data_act, (struct sockaddr *)&remoteaddr_act, (int) sizeof(struct sockaddr)) != 0)
                {
                    printf("trying connection in %s %d\n",inet_ntoa(remoteaddr_act.sin_addr),ntohs(remoteaddr_act.sin_port));
                    sprintf(send_buffer, "425 Something is wrong, can't start the active connection... \r\n");
                    bytes = send(ns, send_buffer, strlen(send_buffer), 0);

                    closesocket(s_data_act);
                }
                else
                {
                    sprintf(send_buffer, "200 Ok\r\n");
                    bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                    printf("Data connection to client created (active connection) \n");
                }
            }

            /**
              * @brief  STOR
              */
            if((strncmp(receive_buffer,"STOR",4)==0))
            {
                memset(&fileName, 0, strlen(fileName));
                wy_fileName_collector(receive_buffer,   fileName);

                if(fopen(fileName,"w")  ==  NULL)
                {
                    printf("@alan:line1\n");
                    sprintf(send_buffer,"450 Requested file action not taken. \r\n");
                    bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                }
                else
                {
                    FILE *fout=fopen(fileName,"w");

                    sprintf(send_buffer,"150 File status okay; about to open data connection. \r\n");
                    bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                    while(1)
                    {
                        n = 0;
                        while(1)
                        {
                            //RECEIVE
                            bytes = recv(s_data_act, &receive_buffer[n], 1, 0);//receive byte by byte...
                            //PROCESS REQUEST
                            if ( bytes <= 0 ) break;

                            if (receive_buffer[n] == '\n')
                            { /*end on a LF*/
                                receive_buffer[n] = '\0';
                                break;
                            }

                            if (receive_buffer[n] != '\r') n++; /*ignore CRs*/
                        }
                        if ( bytes <= 0 ) break;
                        fprintf(fout,"%s\n",receive_buffer);
                    }

                    sprintf(send_buffer,"226 File transfer completed... \r\n");
                    bytes = send(ns, send_buffer, strlen(send_buffer), 0);

                    fclose(fout);
                    closesocket(s_data_act);
                }
            }

            /**
              * @brief  RETR
              */
            if((strncmp(receive_buffer,"RETR",4)==0))
            {
                memset(&fileName, 0, strlen(fileName));
                wy_fileName_collector(receive_buffer,   fileName);

                if(fopen(fileName,"r")==NULL)
                {
                    sprintf(send_buffer,"450 Requested file action not taken. \r\n");
                    bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                }
                else
                {
                    FILE *fin=fopen(fileName,"r");//open tmp.txt file
                    sprintf(send_buffer,"150 Transfering... \r\n");
                    bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                    char temp_buffer[80];
                    while (!feof(fin))
                    {
                        fgets(temp_buffer,78,fin);
                        sprintf(send_buffer,"%s",temp_buffer);
                        send(s_data_act, send_buffer, strlen(send_buffer), 0);
                    }
                    fclose(fin);
                    sprintf(send_buffer,"226 File transfer completed... \r\n");
                    bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                }
                closesocket(s_data_act);
            }



            //LIST or NLST
            if ( (strncmp(receive_buffer,"LIST",4)==0) || (strncmp(receive_buffer,"NLST",4)==0))
            {
                system("dir > tmp.txt");

                FILE *fin=fopen("tmp.txt","r");//open tmp.txt file
                sprintf(send_buffer,"150 Transfering... \r\n");
                bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                char temp_buffer[80];
                while (!feof(fin))
                {
                    fgets(temp_buffer,78,fin);
                    sprintf(send_buffer,"%s",temp_buffer);
                    send(s_data_act, send_buffer, strlen(send_buffer), 0);
                }
                fclose(fin);
                sprintf(send_buffer,"226 File transfer completed... \r\n");
                bytes = send(ns, send_buffer, strlen(send_buffer), 0);

                closesocket(s_data_act);
            }


            //QUIT
            if (strncmp(receive_buffer,"QUIT",4)==0)
            {
                printf("Quit \n");
                sprintf(send_buffer,"221 Connection closed by the FTP client\r\n");
                bytes = send(ns, send_buffer, strlen(send_buffer), 0);
                if (bytes < 0) break;
                closesocket(ns);
            }
        }
        //CLOSE SOCKET
        closesocket(ns);
        printf("disconnected from %s\n",inet_ntoa(remoteaddr.sin_addr));
    }
    closesocket(s);//it actually never gets to this point....use CTRL_C
}

/**
  * @brief  Return file name from the string passed in.
  */
void wy_fileName_collector(char *_buffer, char  *_nameBuffer)
{
    char bf[BUFFERSIZE];
    char sep[2] = " "; //separation is space
    char *word;
    int  wcount=0;

    strcpy(bf, _buffer);
    for (word = strtok(bf, sep);word;word = strtok(NULL, sep))
    {
        wcount++;
        if(wcount == 2) // jump the first space"_".
        {
            strcpy(_nameBuffer, word);
        }
    }
}

关于用 C 代码编写基于 TCP 的 FTP 服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23119615/

有关用 C 代码编写基于 TCP 的 FTP 服务的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  5. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  6. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  7. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  8. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  9. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  10. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

随机推荐