/*
* 这是一个简单ftp服务器代码,server启动后接收客户端LIST GET命令
* 并将命令结果返回客户端
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <dirent.h>
// LIST 命令处理函数
void process_list (int fd)
{
char buf [1500];
DIR *P;
// 遍历本目录下的文件
struct dirent *tmp;
P = opendir (".");
while ((tmp = readdir (P)) != NULL) {
if ((strcmp(tmp->d_name, ".")==0) ||
(strcmp (tmp->d_name, "..") == 0))
continue;
// 把名字读出来,放在发送缓冲区内
bzero (buf, sizeof (buf));
strcpy (buf, tmp->d_name);
// 将文件名发送给客户端
if (send (fd, buf, sizeof (buf), 0) <= 0)
break;
}
}
// 文件下载处理函数
void process_get (int fd, char *cmd)
{
int filefd ;
int nrd;
char buf [1500];
char *p = cmd + 3;
while (*p == ' ')
p ++;
// 打开相应的文件
printf ("Open file = %s\n", p);
filefd = open (p, O_RDONLY);
if (filefd < 0) {
perror ("OPEN GET FILE ERROR!");
return ;
}
//循环读取文件发送文件内容,直到文件读取结束
bzero (buf, sizeof (buf));
while ((nrd = read (filefd, buf, sizeof (buf))) > 0) {
if (send (fd, buf, nrd, 0) <= 0)
break;
bzero (buf, sizeof (buf));
}
close (filefd);
printf ("FILE TRANS DONE!");
}
typedef struct sockaddr SA;
int main (int argc, char *argv[])
{
struct sockaddr_in serveraddr;
struct sockaddr_in clientaddr;
int clientfd, filefd;
int len ;
char buf [1500];
int nrd, scnt;
int ret ;
int on = 1;
// step 1 : socket SOCK_STREAM 0
int sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror ("Create Socket Err!");
exit (-1);
}
setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
// step 2 : bind port ip
bzero (&serveraddr, sizeof (serveraddr));
serveraddr.sin_family = AF_INET; // PF_INET
serveraddr.sin_port = htons (20021); // 端口号的选择,htons
serveraddr.sin_addr.s_addr = inet_addr (argv[1]);
//serveraddr.sin_addr.s_addr = htonl (INADDR_ANY); // 0
if ((ret = bind (sockfd, (SA *)&serveraddr, sizeof (serveraddr))) == -1){
perror ("Bind Err");
exit (-1);
}
// step 3 : listen
if ((ret = listen (sockfd, 5)) == -1) {
perror ("listen Err");
exit (-1);
}
//单循环服务器模型
while (1) {
// step 4 accept
len = sizeof (clientaddr);
clientfd = accept (sockfd, (SA *)&clientaddr, &len);
// step 5 new client accept
if (clientfd < 0) {
perror ("Accept Err!");
continue ;
}
// client connect // client => step 1 send (commond)
printf ("New Client ip=%s: port=%d\n",
inet_ntoa (clientaddr.sin_addr), ntohs (clientaddr.sin_port));
// 阻塞等待客户端命令
bzero (buf, sizeof (buf));
nrd = recv (clientfd, buf, sizeof (buf), 0);
if (nrd <= 0) {
perror ("Recv Client Err!");
close (clientfd);
continue;
}
// 识别两个命令 “LIST”
if (strncmp (buf, "LIST", 4) == 0) {
printf ("Recv List\n");
// 服务器的LIST是遍历目录,把所有文件名发送给客户端
process_list (clientfd);
} else if (strncmp (buf, "GET", 3) == 0) {
printf ("Recv GET\n");
process_get (clientfd, buf);
} else {
printf ("Unknown command!");
}
printf ("Client Close");
close (clientfd);
}
close (sockfd);
return 0;
}