Linux cはtcpファイルサーバとクライアントを実現する
7915 ワード
全体的なニーズ:tcpファイルサーバとクライアントを作成します.クライアントはファイルをアップロードおよびダウンロードできます.
================================================
需要の分割
クライアント機能の説明:
1)help:クライアントのすべてのコマンドと説明を表示し、ローカルで実現すればよい.helpの内容はサーバから返信する必要はない.List:サーバ側からダウンロード可能なファイルのリストが表示され、リストの内容がサーバ側から返される必要があります.get:ダウンロードによって指定されたファイルには、ファイル名のみが含まれ、「/」などの文字タスクがパスであればサポートされません.ダウンロードしたファイルは現在のワークパスの下に保存すればいいです.put:ファイルのアップロードはクライアント本体の合法的な経路でなければならない.クライアントがファイルを検索してサーバquitにプッシュする:クライアントを終了する2)クライアントが起動した後、ユーザーがquitを入力しない限り、コマンドを繰り返し入力することができる.3)コマンド(list/get/put)ごとに接続が確立され、コマンドの実行が完了すると接続が閉じられます.
サーバ側の機能:
1)ファイルサーバは同時サポートを必要とせず、1つの接続、すなわち1つのクライアントが開始した1回のコマンドのみをサポートする.1回のコマンドの実行が完了したら、接続を閉じて次の接続要求を待機します.2)強制的にシャットダウンされない限り、ファイルサーバは起動後も実行されます.3)ファイルサーバ側は、すべてのファイルを格納するためのディレクトリを設定する必要があります.このディレクトリパスは構成可能ではなく、サブディレクトリを含める必要はありません.これを「ファイル格納ディレクトリ」と呼びます.4)listサービスでは,サーバ側が「ファイル格納ディレクトリ」の下からすべてのファイル名を挙げてクライアントに送信する.5)getサービスでは,サーバがユーザが指定したファイル名に基づいてデフォルトで「ファイル格納ディレクトリ」からファイルを検索してクライアントにプッシュするが,プッシュは元のサーバ上のファイルを削除しない.6)putサービスに対して,サーバはユーザがプッシュしたファイルを「ファイル格納ディレクトリ」に格納し,同名のファイルが存在する場合は拒否する.7)コマンドと転送中にエラーが発生した場合は、現在の接続を閉じて次の接続を待機します.ヒント:
符号化する前に、クライアントとサーバ間のコマンド伝送の要求と応答の流れとフォーマットを規定する簡単なアプリケーション層プロトコルを注意深く設計してください.
二.参照コード:
1.サーバ側参照コード
2.クライアントリファレンスコード:
3.検証結果(ubuntu 14.04)
================================================
需要の分割
クライアント機能の説明:
1)help:クライアントのすべてのコマンドと説明を表示し、ローカルで実現すればよい.helpの内容はサーバから返信する必要はない.List:サーバ側からダウンロード可能なファイルのリストが表示され、リストの内容がサーバ側から返される必要があります.get:ダウンロードによって指定されたファイルには、ファイル名のみが含まれ、「/」などの文字タスクがパスであればサポートされません.ダウンロードしたファイルは現在のワークパスの下に保存すればいいです.put:ファイルのアップロードはクライアント本体の合法的な経路でなければならない.クライアントがファイルを検索してサーバquitにプッシュする:クライアントを終了する2)クライアントが起動した後、ユーザーがquitを入力しない限り、コマンドを繰り返し入力することができる.3)コマンド(list/get/put)ごとに接続が確立され、コマンドの実行が完了すると接続が閉じられます.
サーバ側の機能:
1)ファイルサーバは同時サポートを必要とせず、1つの接続、すなわち1つのクライアントが開始した1回のコマンドのみをサポートする.1回のコマンドの実行が完了したら、接続を閉じて次の接続要求を待機します.2)強制的にシャットダウンされない限り、ファイルサーバは起動後も実行されます.3)ファイルサーバ側は、すべてのファイルを格納するためのディレクトリを設定する必要があります.このディレクトリパスは構成可能ではなく、サブディレクトリを含める必要はありません.これを「ファイル格納ディレクトリ」と呼びます.4)listサービスでは,サーバ側が「ファイル格納ディレクトリ」の下からすべてのファイル名を挙げてクライアントに送信する.5)getサービスでは,サーバがユーザが指定したファイル名に基づいてデフォルトで「ファイル格納ディレクトリ」からファイルを検索してクライアントにプッシュするが,プッシュは元のサーバ上のファイルを削除しない.6)putサービスに対して,サーバはユーザがプッシュしたファイルを「ファイル格納ディレクトリ」に格納し,同名のファイルが存在する場合は拒否する.7)コマンドと転送中にエラーが発生した場合は、現在の接続を閉じて次の接続を待機します.ヒント:
符号化する前に、クライアントとサーバ間のコマンド伝送の要求と応答の流れとフォーマットを規定する簡単なアプリケーション層プロトコルを注意深く設計してください.
二.参照コード:
1.サーバ側参照コード
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 128
#define PORT_NUM 8888
typedef struct sockaddr SA;
void ProcessList(int connfd)
{
char buf[N];
DIR *mydir;
struct dirent *myitem;
mydir = opendir(".");
while((myitem = readdir(mydir)) != NULL){
if((strcmp(myitem->d_name, ".") == 0) || (strcmp(myitem->d_name, "..") == 0))
continue;
strcpy(buf, myitem->d_name);
send( connfd, buf, N, 0);
}
close(connfd);
return;
}
void ProcessGet(int connfd, char buf[])
{
int fd,nbyte;
if(( fd = open(buf+1, O_RDONLY)) < 0){
fprintf(stderr, "fail to open %s: %s
",buf+1,strerror(errno));
buf[0] = 'N';
send(connfd, buf, N, 0);
return;
}
buf[0] = 'Y';
send(connfd, buf, N, 0);
while(( nbyte = read( fd, buf, N)) > 0){
send(connfd, buf, nbyte, 0);
}
close(connfd);
return;
}
void ProcessPut(int connfd, char buf[])
{
int fd, nbyte;
if(( fd = open(buf+1, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0){
printf("fail to create %s on server
",buf+1);
return;
}
while(( nbyte = recv( connfd, buf, N, 0)) > 0){
write(fd, buf, nbyte);
}
close(fd);
return;
}
int main(int argc, char *argv[])
{
int listenfd, connfd;
int optval = 1;
char buf[N];
struct sockaddr_in server_addr;
if(( listenfd = socket( AF_INET, SOCK_STREAM, 0)) < 0 ){
fprintf(stderr, "fail to socket: %s
",strerror(errno));
exit(-1);
}
#ifdef _DEBUG_
printf("socket is %d
", listenfd);
#endif
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT_NUM);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if( bind( listenfd, (SA *)(&server_addr), sizeof(server_addr)) < 0){
perror("fail to bind");
exit(-1);
}
listen( listenfd, 5);
while(1){
if(( connfd = accept(listenfd, NULL, NULL)) < 0){
perror("fail to accept");
break;
}
recv( connfd, buf, N, 0);
switch(buf[0]){
case 'L': ProcessList(connfd);
break;
case 'G': ProcessGet(connfd, buf);
break;
case 'P': ProcessPut(connfd, buf);
break;
default: printf("Input ");
}
close(connfd);
}
return 0;
}
2.クライアントリファレンスコード:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 128
#define PORT_NUM 8888
typedef struct sockaddr SA;
void PrintHelp()
{
printf("help: display help info
");
printf("list: get file list of server
");
printf("get : get
");
printf("put : put
");
printf("quit: quit the client
");
return;
}
void ProcessList(struct sockaddr_in server_addr)
{
int sockfd, nbyte;
char buf[N];
if(( sockfd = socket( AF_INET, SOCK_STREAM, 0)) < 0){
printf("fail to list
");
return;
}
if( connect(sockfd, (SA *)(&server_addr), sizeof(server_addr)) < 0){
printf("fail to connect server
");
goto ERROR_1;
}
strcpy(buf, "L");
send(sockfd, buf, N, 0);
while(( nbyte = recv( sockfd, buf, N, 0)) != 0){
printf("%s
",buf);
}
ERROR_1:
close(sockfd);
return;
}
void ProcessGet(struct sockaddr_in server_addr, char command[])
{
int sockfd, nbyte, fd;
char buf[N];
if(( sockfd = socket( AF_INET, SOCK_STREAM, 0)) < 0){
printf("fail to get
");
return;
}
if( connect( sockfd, (SA *)(&server_addr), sizeof(server_addr)) < 0){
printf("fail to connect server
");
goto ERROR_2;
}
sprintf(buf, "G%s", command+4);
send(sockfd, buf, N, 0);
recv(sockfd, buf, N, 0);
if(buf[0] == 'N'){
printf("No such file on server
");
goto ERROR_2;
}
if(( fd = open(command+4, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0){
printf("fail to create local file %s
",command+4);
goto ERROR_2;
}
while(( nbyte = recv(sockfd, buf, N, 0)) > 0){
write(fd, buf, nbyte);
}
close(fd);
ERROR_2:
close(sockfd);
return;
}
void ProcessPut(struct sockaddr_in server_addr, char command[])
{
int sockfd, fd, nbyte;
char buf[N];
if(( sockfd = socket( AF_INET, SOCK_STREAM, 0)) < 0){
printf("fail to get
");
return;
}
if( connect(sockfd,(SA *)(&server_addr),sizeof(server_addr)) < 0){
printf("fail to connect server
");
goto ERROR_3;
}
if((fd = open(command+4, O_RDONLY)) < 0){
printf("fail to open %s
",command+4);
goto ERROR_3;
}
sprintf(buf, "P%s", command+4);
send(sockfd, buf, N, 0);
while(( nbyte = read(fd, buf, N)) > 0){
send(sockfd, buf, nbyte, 0);
}
close(fd);
ERROR_3:
close(sockfd);
return;
}
int main(int argc, char *argv[])
{
int sockfd, fd, nbyte;
char command[32];
struct sockaddr_in server_addr;
if(argc < 3){
printf("Usage: %s
",argv[0]);
exit(-1);
}
if(( sockfd = socket( AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr, "fail to socket: %s
", strerror(errno));
exit(-1);
}
#ifdef _DEBUG_
printf("socket is %d
",sockfd);
#endif
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[2]));
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
//server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
while(1){
printf("");
fgets(command, 32, stdin);
command[strlen(command)-1] = '\0';
if(strcmp( command, "help") == 0){
PrintHelp();
}
else if(strcmp( command, "list") == 0){
ProcessList(server_addr);
}
else if(strncmp( command, "get", 3) == 0){
ProcessGet(server_addr, command);
}
else if(strncmp( command, "put", 3) == 0){
ProcessPut(server_addr, command);
}
else if(strcmp( command, "quit") == 0){
printf("Bye
");
break;
}
else{
printf("Wrong command, 'help' for command list.
");
}
}
return 0;
}
3.検証結果(ubuntu 14.04)