/* TCP FileEcho FTP Client */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "practical.h"
#include "protocol.h"
/* opendir 헤더 */
#include <dirent.h>
/* 함수 선언 부분 */
void FileUploadProcess (int sock);
void FileDownloadProcess (int sock);
void EchoStringProcess (int sock);
void OpendirProcess(int sock);
void ExitProcess(int sock);
void SopendirProcess (int sock);
int main (int argc, char *argv[])
{
/* 입력 파라미터의 개수(argc)가 3인지 검사 */
if (argc != 3)
{
printf ("Usage : %s <Server Address> <Server Port>\n", argv[0]);
exit (1);
}
char *servIP = argv[1];
in_port_t servPort = atoi(argv[2]);
/* socket() : TCP 소켓 생성 */
int sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1)
error_handling ("socket() error");
/* connect() : 서버 연결 요청 */
struct sockaddr_in serv_addr;
memset (&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr (servIP);
serv_addr.sin_port = htons (servPort);
if (connect (sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling ("connect() error");
/* 입력받은 명령어에 따라 분기 처리 */
char operation[BUFSIZE];
memset(operation,0,sizeof(operation));
printf(" welcome FTP & Echo Client !! \n");
printf(" ftp command [ p)ut g)et l)s r)ls e)cho exit)exit - > ");
fgets(operation,BUFSIZE,stdin);
if (strcmp (operation, "p\n") == 0)
FileUploadProcess (sock);
else if (strcmp (operation, "g\n") == 0)
FileDownloadProcess (sock);
else if (strcmp (operation, "l\n") == 0)
OpendirProcess (sock);
else if (strcmp (operation, "e\n") == 0)
EchoStringProcess (sock);
else if (strcmp (operation, "r\n") == 0)
SopendirProcess (sock);
else if (strcmp (operation, "exit\n") == 0)
ExitProcess(sock);
else
printf ("Usage : %s <Server Address> <Server Port>\n", argv[0]);
/* 세션 종료 (close) */
close (sock);
return 0;
}
/* 사용자 함수 선언 부 */
void FileUploadProcess (int sock)
{
/* msgType 전송 : 필드크기는 1바이트로(uint8_t) 고정 */
uint8_t msgType = FileUpReq;
ssize_t numBytesSent = send (sock, &msgType, sizeof (msgType), 0);
if (numBytesSent == -1)
error_handling ("send() error");
else if (numBytesSent != sizeof (msgType))
error_handling ("sent unexpected number of bytes");
/* 파일이름을 서버에 전송 : 필드크기는 256바이트로 고정 */
char fileName[FILENAMESIZE];
memset (fileName, 0, FILENAMESIZE);
printf(" fileName p)ut to server - >");
scanf("%s",fileName);
numBytesSent = send (sock, fileName, FILENAMESIZE, 0);
if (numBytesSent == -1)
error_handling ("send() error");
else if (numBytesSent != FILENAMESIZE)
error_handling ("sent unexpected number of bytes");
/* 파일크기를 서버에 전송 : 필드크기는 4바이트(uint32_t)로 고정 */
struct stat sb;
if (stat (fileName, &sb) < 0)
error_handling ("stat() error");
uint32_t fileSize = sb.st_size;
numBytesSent = send (sock, &fileSize, sizeof (fileSize), 0);
if (numBytesSent == -1)
error_handling ("send() error");
else if (numBytesSent != sizeof (fileSize))
error_handling ("sent unexpected number of bytes");
/* 파일내용을 서버에 전송 : 필드크기는 가변(위 uint32_t 변수의 값 크기 */
FILE *fp = fopen (fileName, "r");
if (fp == NULL)
error_handling ("fopen() error");
printf("[");
while (!feof(fp))
{
char fileBuf[BUFSIZE];
size_t numBytesRead = fread (fileBuf, sizeof (char), BUFSIZE, fp);
if (ferror (fp))
error_handling ("fread() error");
numBytesSent = send (sock, fileBuf, numBytesRead, 0);
if (numBytesSent == -1)
error_handling ("send() error");
else if (numBytesSent != numBytesRead)
error_handling ("sent unexpected number of bytes");
int i= sizeof(numBytesRead); // 센드 사이즈
int k= sizeof(fileSize); // 총 데이터 사이즈
int m=(i*100)/k; // 보낸 크기가 총 데이터의 몇퍼센트인지 계산
if(i<m)
{
printf("#");
}
}
printf("] 100 %% 완료 \n");
fclose (fp); /* 파일 전송 완료 */
/* 서버로부터 ACK 메시지 수신 후 화면에 성공/실패여부를 출력 */
ssize_t FileAckRecv = recv(sock,&msgType,sizeof(msgType),MSG_WAITALL);
if(FileAckRecv == -1)
error_handling(" File recv error ");
if(msgType == FileAck)
printf(" 성공적으로 %s 을(size:%d) 업로드 하였습니다 \n",fileName,fileSize);
else
printf(" 업로드 실패!! 다시 시도해주세요 \n");
}
void EchoStringProcess (int sock)
{
/* msgType 전송 ( 서버측 에코 핸들러 호출 ) */
uint8_t msgType = EchoReq;
ssize_t numBytesSent = send (sock, &msgType, sizeof (msgType), 0);
if (numBytesSent == -1)
error_handling ("send() error");
else if (numBytesSent != sizeof (msgType))
error_handling ("sent unexpected number of bytes");
printf("##### ftp> 에코 서비스가 시작 되었습니다 #####\n");
printf(" ☆ /quit 를 입력 하시면 1 : 1 채팅이 종료 됩니다. ☆\n");
/* echoString 전송 : 필드크기는 가변적, 구현을 위해 socket/src/반이름/04/echo_client.c 참고 */
while(1)
{
/* 입력 받을 버퍼 생성 */
char message[BUFSIZE];
memset(message,0,sizeof(message));
/* 사용자로부터 입력 받음 */
printf("ftp> : ");
fgets(message,BUFSIZE,stdin);
/* 입력 받은 문자 전송 */
size_t echoStringLen = strlen(message);
ssize_t numBytes = send (sock,message, echoStringLen, 0);
if (numBytes == -1)
error_handling ("send() error");
/* 입력 받은 문자가 /quit 일 경우 브레이크 */
if(strcmp(message,"/quit\n") == 0)
break;
/* 서버측으로부터 리시브 */
char buffer[BUFSIZE];
memset(buffer,0,sizeof(buffer));
numBytes = recv(sock,buffer,BUFSIZE,0);
if(numBytes == -1 )
error_handling(" recv() error ");
if(strcmp(buffer,"/quit\n") == 0)
{
printf(" 서버가 1 :1 채팅을 종료 하였습니다.\n");
break;
}
printf("from : %s ",buffer);
}
/* close() : 소켓 종료 */
close(sock);
}
void FileDownloadProcess (int sock)
{
/* 서버에 filedown 함수 호출 msg 전송 */
/* msgType 전송 : 필드크기는 1바이트로(uint8_t) 고정 */
uint8_t msgType = DownReq;
ssize_t numBytesSent = send (sock, &msgType, sizeof(msgType), 0);
if (numBytesSent == -1)
error_handling ("send() error");
else if (numBytesSent != sizeof (msgType))
error_handling(" number of bytes ");
/* 사용자가 다운받을 파일명 서버에 전송 */
char fileName[FILENAMESIZE];
memset(fileName,0,FILENAMESIZE);
printf(" + + 다운 받을 파일명을 입력 하세요 !! + + \n");
printf(" get> ");
scanf("%s",fileName);
numBytesSent = send(sock,fileName,FILENAMESIZE,0);
if (numBytesSent == -1)
error_handling ("file name send() error");
/* 파일명 변경 */
strcat(fileName,"_recvd"); /* TODO Delete */
/* 요청한 파일의 사이즈 수신 */
uint32_t filesize;
ssize_t numBytesRcvd = recv(sock,&filesize,sizeof(filesize),MSG_WAITALL);
if(numBytesRcvd == -1)
error_handling(" recv error ");
else if(numBytesRcvd == 0)
error_handling(" peer connection closed ");
else if(numBytesRcvd != sizeof(filesize))
error_handling(" recv unexpected number of bytes ");
/* 요청한 파일의 내용을 수신 */
FILE* fp = fopen(fileName,"w");
if(fp == NULL)
error_handling("fopen error");
uint32_t rcvdFileSize = 0;
printf("[ ");
while (rcvdFileSize < filesize)
{
char fileBuf[BUFSIZE];
numBytesRcvd = recv (sock, fileBuf, BUFSIZE, 0);
if (numBytesRcvd == -1)
error_handling ("recv() error");
else if (numBytesRcvd == 0)
error_handling ("peer connection closed");
fwrite (fileBuf, sizeof (char), numBytesRcvd, fp);
if (ferror (fp))
error_handling ("fwrite() error");
rcvdFileSize += numBytesRcvd;
/* 수신 상태 출력 */
int i = sizeof(numBytesRcvd);
int k = sizeof(filesize);
int m=(i*100)/k;
if(i<m)
{
printf("#");
}
}
printf("] 100 %% 완료 \n");
fclose (fp); /* 파일 수신 완료 */
/* 수신 완료 메시지 전송 , 리시브 완료 된 후 전송함 */
if(rcvdFileSize ==filesize)
{
msgType=DownAck;
ssize_t msgAckSent = send(sock,&msgType,sizeof(msgType),0);
if(msgAckSent == -1)
error_handling(" ack 메시지 전송 실패 ");
printf(" %s 파일(size:%d) 을 다운로드 하였습니다.\n",fileName,filesize);
}
else
printf(" 다운로드 실패 \n ");
}
void OpendirProcess (int sock)
{
DIR *dp;
struct dirent *d;
/* 파일 개방 */
dp=opendir(".");
if(dp == NULL)
error_handling(" open dir() error");
printf(" + + + + + + + + + + + + + + + + + + +\n");
printf("##### 내컴퓨터 디텍토리 내용입니다. #####\n");
/* 파일 읽기 */
while((d=readdir(dp))!=NULL)
{
/* 불필요한 내용 빼고 출력 */
if(!strcmp(d->d_name,".") || !strcmp(d->d_name,"..") || !strcmp(d->d_name,".svn")) continue;
fprintf(stdout,"%s\n",d->d_name);
}
printf(" + + + + + + + + + + + + + + + + + + +\n");
printf("##### 출력이 완료 되었습니다. ###### \n");
/* 기타 명령어 추가 */
char cmd[100];
char buf[BUFSIZE];
while(1)
{
fputs("\n",stdout);
printf(" -----++☆ ls Command Mode ☆++------- \n");
printf(".. [ cd | getcwd | ls | exit ] ..\n");
fputs("\n",stdout);
printf("cmd> ");
scanf("%s",cmd);
/* getcwd : 현재 디텍토리 위치 출력 */
if(strcmp(cmd,"getcwd") == 0 )
{
if(getcwd(buf,BUFSIZE)== NULL)
error_handling(" getcwd error");
fputs("\n",stdout);
printf(" + ■ 현재 위치 : %s\n",buf);
}
/* cd : 디텍토리 이동 */
if(strcmp(cmd,"cd") ==0)
{
printf("@@ 이동할 경로를 입력 하세요. @@ \n");
scanf("%s",buf);
if(chdir(buf)== -1)
error_handling(" cd command error");
printf("@@ %s 으로 이동 하였습니다. @@ \n",buf);
}
/* ls : 현재 디텍토리 내용 출력 */
if(strcmp(cmd,"ls") ==0)
{
printf(" + + + + + + + + + + + + + + + + + + +\n");
dp=opendir(".");
if(dp == NULL)
error_handling(" open dir() error");
while((d=readdir(dp))!=NULL)
{
if(!strcmp(d->d_name,".") || !strcmp(d->d_name,"..") || !strcmp(d->d_name,".svn")) continue;
fprintf(stdout,"%s\n",d->d_name);
}
printf(" + + + + + + + + + + + + + + + + + + +\n");
printf("##### 출력이 완료 되었습니다. ###### \n");
fputs("\n",stdout);
}
if(strcmp(cmd,"exit")==0)
{
break;
}
}
closedir(dp);
}
void SopendirProcess (int sock)
{
/* 총괄적인 rls 프로세서 호출 메시지 전송 */
uint8_t msgType = DirReq;
ssize_t numBytesSent = send (sock, &msgType, sizeof (msgType), 0);
if (numBytesSent == -1)
error_handling ("send() error");
else if (numBytesSent != sizeof (msgType))
error_handling ("sent unexpected number of bytes");
/* 접속 인사말 */
printf("|-------------------------------------|\n");
printf("|.........Welcome to Server ..........|\n");
printf("|.....................................|\n");
printf("|.........♥ Command List ♥ ..........|\n");
printf("|.....................................|\n");
printf("|[ rls | rcd | rcwd | exit ]|\n");
printf("|.....................................|\n");
printf("|1. rls : 디텍토리 리스트 |\n");
printf("|2. rcd : 디텍토리 이동 |\n");
printf("|3. rcwd : 현재 위치 |\n");
printf("|4. exit : 종료 |\n");
printf("..................♡...................|\n");
/* 사용자 입력에 따른 명령어 처리 */
while(1)
{
char cmd[BUFSIZE];
printf(" .' ★ rls Command List ★ '. \n");
printf("[ rls | rcd | rcwd | exit ] \n");
fputs("\n",stdout);
printf("cmd > ");
fgets(cmd,BUFSIZE,stdin);
/* 사용자 명령 요청 송신 */
ssize_t cmdsend = send(sock,cmd,BUFSIZE,0);
if(cmdsend == -1)
error_handling(" user cmd send error ");
/* 사용자 명령 요청에 따른 데이터 처리 */
if(strcmp(cmd,"rls\n")==0)
{
printf(" + + + + + 서버 디텍토리를 출력 합니다. + + + + + \n ");
/* 서버 디텍토리 버퍼 내용 리시브 */
char recvbuf[BUFSIZE];
memset(recvbuf,0,sizeof(recvbuf));
ssize_t numBytesRcvd = recv(sock,recvbuf,BUFSIZE,0);
if(numBytesRcvd == -1)
error_handling("recv error");
printf("%s",recvbuf);
printf(" ++ 서버 디텍토리 출력이 완료 되었습니다. ++ \n");
fputs("\n",stdout);
}
if(strcmp(cmd,"rcd\n")==0)
{
/* 이동할 위치 입력 받음 */
char rcdbuf[BUFSIZE];
memset(rcdbuf,0,sizeof(rcdbuf));
printf(" ++ 이동할 위치를 입력 하세요. ++ \n");
printf(" 위치 작성 예) /home/guest/\n");
printf(" cmd > ");
fgets(rcdbuf,BUFSIZE,stdin);
/* 개행문자 (\n) 제거 이유 : 개행문자있을시, 서버측 에러 */
rcdbuf[strlen(rcdbuf)-1]='\0';
/* 이동할 위치 전송 */
ssize_t sendbuf = send(sock,rcdbuf,BUFSIZE,0);
if(sendbuf == -1)
error_handling(" send () error ");
printf(" ++ %s 로 이동 하였습니다. \n",rcdbuf);
fputs("\n",stdout);
}
if(strcmp(cmd,"rcwd\n")==0)
{
printf("☆ 현재 서버 디텍토리 위치를 요청 합니다 ☆ \n");
/* 현재 서버 디텍토리 위치 리시브 */
char cwdbuf[BUFSIZE];
ssize_t cwdsend = recv(sock,cwdbuf,BUFSIZE,0);
if(cwdsend == -1)
error_handling(" cwd send error");
printf(" 현재 위치 : %s \n",cwdbuf);
fputs("\n",stdout);
}
/* 사용자 명령 exit 처리 */
if(strcmp(cmd,"exit\n")==0)
{
ssize_t rcvdbuf = recv(sock,cmd,strlen(cmd),0);
if(rcvdbuf == -1)
error_handling(" exit recv error ");
printf(" FTP 가 종료 됩니다. \n");
break;
}
}
}
// 종료 프로세서
void ExitProcess(int sock)
{
exit(0);
close(sock);
}
'C 프로젝트 > C 프로젝트' 카테고리의 다른 글
Socket Programin in C , 2번째 !! Simple FTP ( Client) (0) | 2012.12.18 |
---|---|
심플한 1 : 1 채팅 프로그램 ( 클라이언트 ) (0) | 2012.12.18 |
소켓 프로그래밍 첫번째 ! 1:1 채팅 프로그램 (서버 ) (0) | 2012.12.18 |