我们在之前的文章中,曾经对FTP文件传输协议做过详细的先容。本章,我们对如何用C语言实现FTP服务器做一个简朴的先容。概述FTP文件传输协议,是因特网上使用得最广泛的文件传输协议。
FTP提供交互式的会见,允许客户指明文件的花样与类型,并允许文件具有存储权限。FTP屏蔽了差别操作系统之前的细节,因此适合在异构网络中任意盘算机之间传送文件。FTP的基本事情原理FTP使用C/S方式,一个FTP服务器可以为多个客户历程提供服务,FTP服务器历程由两大部门组成:一个主历程,卖力吸收新的请求;另外有若干个附属历程,卖力处置惩罚单个请求。主历程的事情步骤如下:打开端口号(一般为21),使客户端能通过此端口号会见;等候客户端发出毗连请求;启动附属历程来处置惩罚客户历程发来的请求。
附属历程对客户历程的请求处置惩罚完后即终止,附属历程在运行期间可能会凭据需要另外建立其他一些历程。回到等候状态,继续等候其他客户历程发来的毗连请求。主历程和附属历程是并发举行的。
在举行文件传输时,FTP的客户和服务器之间要建设两个并行的TCP毗连:“控制毗连”和“数据毗连”。控制毗连在整个会话期间一直保持打开,FTP客户所发出的传送请求,通过控制毗连发送给服务器端的控制历程,可是控制毗连并不会用于传输数据。实际传输文件的是“数据毗连”。
服务器端的控制历程在吸收到FTP客户发送来的文件传输请求后,就会建立“数据传送历程”和“数据毗连”,用来毗连客户端和服务器端的数据传送历程。由于FTP使用了一个分散的控制毗连,因此FTP的控制信息是带外控制的。当客户历程向服务器历程发出建设毗连请求时,通过服务器端口号21请求毗连,同时会告诉服务器历程自己用于建设数据传送毗连的另一个端口号。
服务器一般使用端口号20同客户历程建设数据毗连,由于FTP使用两个差别的端口号,所以数据毗连和控制毗连不会发生杂乱。综上所述,我们可以画出基本的算法流程图代码实现:首先是基本的界说/* Commands enumeration */typedef enum cmdlist { ABOR, CWD, DELE, LIST, MDTM, MKD, NLST, PASS, PASV, PORT, PWD, QUIT, RETR, RMD, RNFR, RNTO, SITE, SIZE, STOR, TYPE, USER, NOOP} cmdlist;/* String mappings for cmdlist */static const char *cmdlist_str[] = { "ABOR", "CWD", "DELE", "LIST", "MDTM", "MKD", "NLST", "PASS", "PASV", "PORT", "PWD", "QUIT", "RETR", "RMD", "RNFR", "RNTO", "SITE", "SIZE", "STOR", "TYPE", "USER", "NOOP" };控制端口的界说/* define FTP control port */#define CONTROLPORT 21主函数/** * Sets up server and handles incoming connections * @param port Server port */int main(){ int sock = create_socket(CONTROLPORT ); struct sockaddr_in client_address; int len = sizeof(client_address); int connection, pid, bytes_read; while(1){ connection = accept(sock, (struct sockaddr*) &client_address,&len); char buffer[BSIZE]; Command *cmd = malloc(sizeof(Command)); State *state = malloc(sizeof(State)); pid = fork(); memset(buffer,0,BSIZE); if(pid<0){ fprintf(stderr, "Cannot create child process."); exit(EXIT_FAILURE); } if(pid==0){ close(sock); char welcome[BSIZE] = "220 "; if(strlen(welcome_message)<BSIZE-4){ strcat(welcome,welcome_message); } else{ strcat(welcome, "Welcome to nice FTP service."); } /* Write welcome message */ strcat(welcome,"n"); write(connection, welcome,strlen(welcome)); /* Read commands from client */ while (bytes_read = read(connection,buffer,BSIZE)){ signal(SIGCHLD,my_wait); if(!(bytes_read>BSIZE)){ /* TODO: output this to log */ buffer[BSIZE-1] = '