간단한 ftp 서버 클라이언트 작성 중 질문입니다.

sm106의 이미지

소스코드입니다.

 
//server
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <string.h>
 
#define MAXLINE 512
#define MAX_SOCK 64
#define TRUE 1
 
char *escapechar = "bye";
int getmax(int);
void removeClient(int);
int getDottedIP(int sd, struct sockaddr_in *addr);
/*
 * 새로운 시그널 처리 함수 선언 
 */
void my_signal(int signo); 
 
int maxfdp1;           
int num_chat = 0;      
int s;                 
int client_s[MAX_SOCK],client_depth[MAX_SOCK];
FILE *lfp[MAX_SOCK];
 
/*****************************************************************************
    함  수  명 : main
    파라메터   : 
    리  턴  값 : 
    작  성  일 : 
    최종변경일 : 
    설      명 : 서버 포트는 4001번으로 bind 한다.
******************************************************************************/
int main(int argc, char *argv[]) 
{
    char rline[MAXLINE+1];
    char *start_echo = "Connected to chat-server\n"
	              ">> ftp id:";
	char *password_echo = "Connected to chat-server\n"
	              ">> ftp password:";
	char *command_echo = "Connected to chat-server\n"
	              ">> ftp command:";
	char *filename_echo = "Connected to chat-server\n"
	              ">> ftp filename:";
    int i, j, n;
    int client_fd, clilen;
 
    fd_set read_fds; /* 일기 감지할 소켓번호 구조체 */
    struct sockaddr_in client_addr, server_addr;
 
 
 
    /* 초기소켓 생성 */
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
	{
        printf("Server: Can't open stream socket.");
        exit(0);
    }
 
    /* server_addr 구조체의 내용 세팅 */
    bzero((char *)&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi("4001"));
 
    if (bind(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
	{
        printf("Server: Can't bind local address.\n");
        exit(0);
    }
 
    if (signal(SIGINT, my_signal) == SIG_ERR) 
	{ 
		/* Ctrl+C */
        printf("Server: signal(SIGINT) error\n");
        exit(0);
    }
 
    if (signal(SIGTERM, my_signal) == SIG_ERR) 
	{ 
		/* software termination */
        printf("Server: signal(SIGTERM) error\n");
        exit(0);
    }
 
    if (signal(SIGQUIT, my_signal) == SIG_ERR) 
	{ 
		/* Ctrl+\ */
        printf("Server: signal(SIGQUIT) error\n");
        exit(0);
    }
 
    /* 클라이언트로부터 연결요청을 기다림 */
    listen(s, 5); /* backlog = 5 */
 
    maxfdp1 = s + 1; /* 최대 소켓번호+1 */
 
    while (1) 
	{
        FD_ZERO(&read_fds);
        FD_SET(s, &read_fds);
        for (i=0; i < num_chat; i++)
		{
            FD_SET(client_s[i], &read_fds);
		}
 
	    maxfdp1 = getmax(s) + 1; /* maxfdp1 재 계산 */
 
	    if (select(maxfdp1, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) {
            printf("Server: select error <= 0\n");
            break;
        }
 
        if (FD_ISSET(s, &read_fds)) 
		{
            clilen = sizeof(client_addr);
            client_fd = accept(s, (struct sockaddr *)&client_addr, &clilen);
 
	        if (client_fd == -1) {
                printf("Server: accept error\n");
                break;
            }
 
            /* 채팅 클라이언트 목록에 추가 */
            client_s[num_chat] = client_fd;
			client_depth[num_chat]=100;
            num_chat++;
            send(client_fd, start_echo, strlen(start_echo), 0);
 
            if (getDottedIP(client_fd, &client_addr) > -1)
                printf("%d session(ip: %s)\n", num_chat, inet_ntoa(client_addr.sin_addr));
            else
                printf("%d session\n", num_chat);
        }
 
        /* 클라이언트가 보낸 메시지를 모든 클라이언트게 방송 */
        for (i=0; i < num_chat; i++) 
		{
            if (FD_ISSET(client_s[i], &read_fds)) 
			{
                if ((n = recv(client_s[i], rline, MAXLINE, 0)) <= 0)
				{
                    /* 비 정상 종료도 검사가 됨 */
                    removeClient(i); /* abrupt exit */
                    continue;
                }
                rline[n] = '\0';
 
                /* 종료문자 처리 */
                if (strstr(rline, escapechar) != NULL) {
                    removeClient(i); /* abrupt exit */
                    continue;
                }
 
				if(client_depth[i]==100)
				{
					send(client_fd, password_echo, strlen(password_echo), 0);
					client_depth[i]=200;
				}
				else if(client_depth[i]==200)
				{
                    send(client_fd, command_echo, strlen(command_echo), 0);
					client_depth[i]=300;
				}
				else if(client_depth[i]==300)
				{
                    send(client_fd, filename_echo, strlen(filename_echo), 0);
					client_depth[i]=400;
				}
				else if(client_depth[i]==400)  /* get 일경우 */
				{
					if((lfp[i]=fopen(rline,"w"))==NULL) 
					{
						removeClient(i); /* abrupt exit */
                        continue;
					}
					client_depth[i]=500;
    			}
				else if(client_depth[i]==500)
				{
                    fwrite(rline,1,n,lfp[i]);
					if(lfp[i] != NULL) fclose(lfp[i]);
				}
            }
       }
  } /* while */
 
  my_signal(SIGIO);
}
 
/*****************************************************************************
    함  수  명 : removeClient
    파라메터   : 
    리  턴  값 : 
    작  성  일 : 
    최종변경일 : 
    설      명 :
******************************************************************************/
void removeClient(int i) 
{
    struct sockaddr_in client_addr;
 
    if (getDottedIP(client_s[i], &client_addr) > -1)
    printf("@@FTP SESSION DELETE.(IP: %s).\n", inet_ntoa(client_addr.sin_addr));
    else
    printf("@@FTP SESSION DELETE.\n");
 
    close(client_s[i]);
    if (i != num_chat-1)
	{
        client_s[i] = client_s[num_chat-1];
	}
    num_chat--;
 
    printf("@@NOW FTP SESSION COUNT = [%d]\n", num_chat);
}
 
/*****************************************************************************
    함  수  명 : removeClient
    파라메터   : 
    리  턴  값 : 
    작  성  일 : 
    최종변경일 : 
    설      명 : client_s[] 내의 최대 소켓번호 얻기(초기치는 k)
******************************************************************************/
int getmax(int k) {
  int max = k;
  int r;
  for (r=0; r < num_chat; r++)
    if (client_s[r] > max)
      max = client_s[r];
  return max;
}
 
/*****************************************************************************
    함  수  명 : removeClient
    파라메터   : 
    리  턴  값 : 
    작  성  일 : 
    최종변경일 : 
    설      명 : 소켓에 연결된 상대방 주소를 알아낸다
******************************************************************************/
int getDottedIP(int sd, struct sockaddr_in *addr) {
  struct sockaddr_in client_addr;
  int len, r;
 
  len = sizeof(client_addr);
  if ((r = getpeername(sd, (struct sockaddr *)&client_addr, &len)) == 0)
    *addr = client_addr;
  return r;
}
 
/*****************************************************************************
    함  수  명 : removeClient
    파라메터   : 
    리  턴  값 : 
    작  성  일 : 
    최종변경일 : 
    설      명 : 시그널 처리 함수 정의
	             대부분의 시그널(SIGILL과 SIGTRAP 은 제외)에 대한 처리 함수는 시그널이 포작된 후
                 즉시 재지정된다. 이것은 프로세스가 시그널의 처리 함수를 잊어버리고, 다음에 시그널이
	             도착하면 묵시적 처리함수인 SIG_DFL 을 수행하는 것을 의미한다.
                 이것은 특히 사용자가 인터럽트키를 여러번 누를 수도 있는 대화명 프로그램에서 문제가 된다
                 그러므로 시그널 함수가 호출되자 마자 SIGINT 시그널을 무시한다 
******************************************************************************/
void my_signal(int signo) {
  int i;
 
  signal(SIGINT, SIG_IGN);
  signal(SIGTERM, SIG_IGN);
  signal(SIGQUIT, SIG_IGN);
 
  /* 모든 열려있는 소켓을 닫는다 */
  close(s);
  for (i=0; i < num_chat; i++)
    close(client_s[i]);
 
  exit(0);
}
 
 
 
//client
 
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <string.h>
 
#define MAXLINE 512
#define MAX_SOCK 128
#define TRUE 1
 
char *escapechar = "bye";
/*****************************************************************************
    함  수  명 : main
    파라메터   : 
    리  턴  값 : 
    작  성  일 : 
    최종변경일 : 
    설      명 : 
******************************************************************************/
int main(int argc, char *argv[]) 
{
    char line[MAXLINE], message[MAXLINE+1];
    struct sockaddr_in server_addr;
    int maxfdp1;
    int s, k;
    fd_set read_fds;
	FILE *lfp=NULL;
 
    /* 소켓 생성 */
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        printf("Client: Can't open stream socket.\n");
        exit(0);
    }
 
    /* 채팅 서버의 소켓주소 구조체 server_addr 초기화 */
    bzero((char *)&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(atoi("4001"));
 
    /* 연결요청 */
    if (connect(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
	{
        printf("Client: Can't connect to server.\n");
        exit(0);
    } 
 
    maxfdp1 = s + 1;
    FD_ZERO(&read_fds);
 
    while (1) 
	{
        FD_SET(0, &read_fds);
        FD_SET(s, &read_fds);
 
        if (select(maxfdp1, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) {
            printf("Client: select error\n");
            break;
        }
 
        if (FD_ISSET(s, &read_fds)) 
		{
            int size;
            if ((size = recv(s, message, MAXLINE, 0)) <= 0)
		    break;
 
            /*--
			if (message[size-1] != '\n')
            message[size++] = '\n';
			--*/
            message[size] = '\0';
 
            printf("%s", message);
        }
 
        if (FD_ISSET(0, &read_fds)) {
            if(strstr(message,"filename") != NULL) 
			{
                if (fgets(message, MAXLINE, stdin)) 
			    {
                   k=0;
                   for(;;)
				   {
					   if(message[k]==0x00)
					   {
						   message[k-1]=0x00;
						   break;
					   }
					   k++;
				   }
 
                   sprintf(line,"%s",message);
 
		           if (send(s, line, strlen(line), 0) < 0) 
				   {
                       printf("Client: Write error on socket.\n");
                       break;
                   }
 
  	               if (strstr(message, escapechar) != NULL) 
				   {
                       printf("Good by client.\n");
                       break;
                   }
               }
 
			   if((lfp=fopen(message,"rt"))==NULL) exit(0);
 
			   fgets(line,sizeof(line),lfp);
 
			   if (send(s, line, strlen(line), 0) < 0) 
			   {
                   printf("Client: Write error on socket.\n");
                   break;
               }
 
		       if(lfp != NULL) fclose(lfp);
	       }
		   else
		   {
                if (fgets(message, MAXLINE, stdin)) 
			    {
                   k=0;
                   for(;;)
				   {
					if(message[k]==0x00)
					{
						message[k-1]=0x00;
						break;
					}
					k++;
				   }
 
                   sprintf(line,"%s",message);
 
		           if (send(s, line, strlen(line), 0) < 0) 
				   {
                       printf("Client: Write error on socket.\n");
                       break;
                   }
 
  	               if (strstr(message, escapechar) != NULL) 
				   {
                       printf("Good by client.\n");
                       break;
                   }
               }
		   }
       }
   }
   close(s);
   return TRUE;
}

get이나 put 명령어 입력시 세션이 종료되어 버리는데 원인을 모르겠습니다.
도와주시겠어요??

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.