一、客户端
功能:
- 通过get获取服务器的文件并下载到客户端本地自定义文件夹中
- 通过list查看服务器的文件
核心代码:
#include <stdio.h>
#include <stdlib.h>
#include "unp.h"
void ftp_cli(FILE *fp, int sockfd);
ssize_t Readline2(int fd, void *ptr, size_t maxlen);
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: tcpcli <IPaddress>");
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(21000);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
ftp_cli(stdin, sockfd); /* do it all */
exit(0);
}
void ftp_cli(FILE *fp, int sockfd)
{
char sendline[MAXLINE], recvline[MAXLINE];
char cmd [MAXLINE];
char wdpath[200];
if(getcwd(wdpath,200)==NULL)return ;
strcat(wdpath,"/clidir");
for ( ; ; )
{
fprintf(stderr, "myftpclient-->");
if (Fgets(sendline, MAXLINE, fp) == NULL) return;
//else fputs(sendline,stdout);
strcpy(cmd,sendline);
//int i;
//for(i=0;i<strlen(sendline);i++)
//fprintf(stderr,"%d\n",(int)(sendline[i]));
char * pcmd=strtok(cmd," \n");
if(strcmp(pcmd,"dir")==0||strcmp(pcmd,"ls")==0||strcmp(pcmd,"list")==0)
{
Writen(sockfd, sendline, strlen(sendline));
if (Readline2(sockfd, recvline, MAXLINE) == 0)
err_quit("str_cli: server terminated prematurely");
int lines=atoi(recvline);
int i;
for(i=0;i<lines;i++)
{
Readline2(sockfd, recvline, MAXLINE);
fprintf(stderr,recvline);
}
}
else if(strcmp(pcmd,"get")==0)
{
Writen(sockfd, sendline, strlen(sendline));
if (Readline2(sockfd, recvline, MAXLINE) == 0)
err_quit("str_cli: server terminated prematurely");
int bytes=atoi(recvline);
fprintf(stderr, "file length = %d.\n",bytes);
int left=bytes;
FILE *fp=0;
if(left>0)
{
char filename[100];
strcpy(filename,wdpath);
strcat(filename,"/");
strcat(filename, strtok(NULL," \n"));
if((fp=fopen(filename,"wb"))==NULL)
{
fprintf(stderr,"failed open file %s",filename);
return;
}
fprintf(stderr, "file create: %s.\n",filename);
}
while(left>MAXLINE)
{
Readn(sockfd, recvline, MAXLINE);
left-=MAXLINE;
fwrite(recvline,MAXLINE,1,fp);
}
if(left<=MAXLINE)
{
Readn(sockfd, recvline, left);
//fprintf(stderr,recvline);
fwrite(recvline,left,1,fp);
}
fprintf(stderr, "file writen done.\n");
fclose(fp);
}
else if(strcmp(pcmd,"quit")==0)
{
fprintf(stderr, "See you!.\n");
return;
}
else if(strcmp(pcmd,"delete")==0){
Writen(sockfd,sendline,strlen(sendline));
if (Readline2(sockfd, recvline, MAXLINE) == 0){
err_quit("str_cli: server terminated prematurely");
}else
fprintf(stderr,"file %s delete successfully.\n",recvline);
}else if(strcmp(pcmd,"put") == 0){
Writen(sockfd, sendline, strlen(sendline));
char filename[100];
strcpy(filename,wdpath);
strcat(filename,"/");
strcat(filename,strtok(NULL," \n"));
FILE *fp = 0;
if((fp = fopen(filename,"rb")) == NULL){
fprintf(stderr,"failed open file %s",filename);
return;
}
fprintf(stderr,"open file %s.\n",filename);
long filelen;
fseek(fp,0,SEEK_END);
filelen = ftell(fp);
rewind(fp);
char flen[7];
sprintf(flen,"%d\n",(int)filelen);
fprintf(stderr,"filesize %s\n",flen);
Writen(sockfd,flen,strlen(flen));
fprintf(stderr,"sent filesize=%s",flen);
long left = filelen;
while(left > MAXLINE){
fread(sendline,MAXLINE,1,fp);
Writen(sockfd,sendline,MAXLINE);
left -= MAXLINE;
}
if(left <= MAXLINE){
fread(sendline,left,1,fp);
Writen(sockfd,sendline,left);
}
fprintf(stderr,"file send done.\n");
fclose(fp);
}else{
fprintf(stderr, "usage:cmd [args].\ncmd=\tdir\tls\tget\tquit\n");
}
}
}
ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++) {
again:
if ( (rc = read(fd, &c, 1)) == 1) {
*ptr++ = c;
if (c == '\n')
break; /* newline is stored, like fgets() */
} else if (rc == 0) {
*ptr = 0;
return(n - 1); /* EOF, n - 1 bytes were read */
} else {
if (errno == EINTR)
goto again;
return(-1); /* error, errno set by read() */
}
}
*ptr = 0; /* null terminate like fgets() */
return(n);
}
/* end readline */
ssize_t
Readline2(int fd, void *ptr, size_t maxlen)
{
ssize_t n;
if ( (n = readline(fd, ptr, maxlen)) < 0)
err_sys("readline error");
return(n);
}
二、服务端
功能:
- 监听来自客户端的请求,服务器里面的文件都存放在服务器本地自定义文件夹中
核心代码:
#include "unp.h"
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
void ftpserv(int sockfd);
void sig_chld(int signo);
ssize_t Readline2(int fd, void *ptr, size_t maxlen);
int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int);
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(21000);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
Signal(SIGCHLD, sig_chld); /* must call waitpid() */
for ( ; ; )
{
clilen = sizeof(cliaddr);
if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0)
{
if (errno == EINTR)
continue; /* back to for() */
else
err_sys("accept error");
}
if ( (childpid = Fork()) == 0)
{ /* child process */
Close(listenfd); /* close listening socket */
ftpserv(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
void ftpserv(int sockfd)
{
ssize_t n;
char buf[MAXLINE];
char sendline[MAXLINE],recvline[MAXLINE];
char wdpath[200];
if(getcwd(wdpath,200)==NULL)return ;
strcat(wdpath,"/user");
char dirname[1000];
char dirlen[7];
DIR *pdir;
struct dirent *pent;
if ((pdir = opendir(wdpath)) == NULL)
{
fprintf(stderr, "open dir failed.\n");
return;
}
again:
while ( (n = Readline2(sockfd, buf, MAXLINE)) > 0)
{
//Writen(sockfd, buf, n);
fprintf(stderr,"n=%d\nbuf=%s",n,buf);
char * cmd=strtok(buf," \n");
if( strcmp(cmd,"dir") ==0 || strcmp(cmd,"ls")==0 || strcmp(cmd,"list")==0)
{
char * pdirname=dirname;
int lines=0;
while (1)
{
pent = readdir(pdir);
if (pent == NULL) break;
// fprintf(stderr, "%5d %s\n",pent->d_ino, pent->d_name);
strcpy(pdirname,pent->d_name);
strcat(pdirname,"\r\n");
fprintf(stderr, "%d %s",strlen(pdirname), pdirname);
lines++;
pdirname+=strlen(pent->d_name)+2;
}
*pdirname=0;
sprintf(dirlen,"%d\n",lines);
fprintf(stderr,"lines %d\n",lines);
Writen(sockfd, dirlen, strlen(dirlen));
Writen(sockfd,dirname,strlen(dirname));
rewinddir(pdir);
}
else if(strcmp(cmd,"get")==0)
{
char filename[100];
strcpy(filename,wdpath);
strcat(filename,"/");
strcat(filename, strtok(NULL," \n"));
FILE *fp=0;
if((fp=fopen(filename,"rb"))==NULL)
{
fprintf(stderr,"failed open file %s",filename);
return;
}
fprintf(stderr, "open file %s.\n",filename);
long filelen;
fseek(fp,0,SEEK_END);
filelen=ftell(fp);
rewind(fp);
char flen[7];
sprintf(flen,"%d\n",(int)filelen);
fprintf(stderr,"filesize %s\n",flen);
Writen(sockfd, flen, strlen(flen));
fprintf(stderr, "sent filesize=%s",flen);
long left=filelen;
while(left>MAXLINE)
{
fread(sendline,MAXLINE,1,fp);
Writen(sockfd, sendline, MAXLINE);
left-=MAXLINE;
}
if(left<=MAXLINE)
{
fread(sendline,left,1,fp);
Writen(sockfd, sendline, left);
}
fprintf(stderr, "file sent done.\n");
fclose(fp);
} /**/
else if(strcmp(cmd,"put")==0){
if(Readline2(sockfd,recvline,MAXLINE) == 0){
err_quit("str_cli: client terminated prematurely");
}
int bytes = atoi(recvline);
fprintf(stderr,"file length = %d.\n",bytes);
int left = bytes;
FILE *fp = 0;
if(left > 0){
char filename[100];
strcpy(filename,wdpath);
strcat(filename,"/");
strcat(filename,strtok(NULL," \n"));
if((fp = fopen(filename,"wb")) == NULL){
fprintf(stderr,"failed open file %s",filename);
return;
}
fprintf(stderr,"file create: %s.\n",filename);
}
while(left > MAXLINE){
Readn(sockfd,recvline,MAXLINE);
left -= MAXLINE;
fwrite(recvline,MAXLINE,1,fp);
}
if(left <= MAXLINE){
Readn(sockfd,recvline,left);
fwrite(recvline,left,1,fp);
}
fprintf(stderr,"file writen done.\n");
fclose(fp);
}
else if(strcmp(cmd,"delete")==0){
char filename[100];
char name[30];
strcpy(filename,wdpath);
strcat(filename,"/");
strcat(filename,strtok(NULL," \n"));
printf("filename is %s\n",filename);
sprintf(name,"%s\n",filename);
Writen(sockfd,name,strlen(name));
if(remove(filename) == 0){
fprintf(stderr,"file delete successfully.\n");
}else{
fprintf(stderr,"file don't exist.\n");
}
}
else
{}
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys(" read error");
//closedir(pdir);
}
fprintf(stderr,"n=%d\nbuf=%s",n,buf);
}
void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++) {
again:
if ( (rc = read(fd, &c, 1)) == 1) {
*ptr++ = c;
if (c == '\n')
break; /* newline is stored, like fgets() */
} else if (rc == 0) {
*ptr = 0;
return(n - 1); /* EOF, n - 1 bytes were read */
} else {
if (errno == EINTR)
goto again;
return(-1); /* error, errno set by read() */
}
}
*ptr = 0; /* null terminate like fgets() */
return(n);
}
/* end readline */
ssize_t
Readline2(int fd, void *ptr, size_t maxlen)
{
ssize_t n;
if ( (n = readline(fd, ptr, maxlen)) < 0)
err_sys("readline error");
return(n);
}
三、用法
服务器部分:
- 执行make clean与make
- 运行命令
./ftps
客户端部分:
- 执行make clean与make
- 运行命令
./ftpc 127.0.0.1
注意:./ftps
要先于./ftpc 127.0.0.1
运行
四、UNP
客户端与服务器的编译都是依赖了libunp.a静态库,因此,在make之前最好在自己的环境里面编译得到新的libunp.a,然后替换文件夹里面旧的静态链接库,再make。
- 解压unpv13e.tar.gz
- 进入目录执行
./configure
cd lib //进入lib目录
make //执行make命令
- 把新生成的libunp.a替换旧的libunp.a