소켓을 이용하여 원하는 파일을 복사하기에 관한 질문입니다.

pooh311의 이미지

다 짰다고 생각하고 돌려봤는데 몇가지 문제가 생겨서 올려봅니다.

첫번째 문제..
server에서 특정 폴더의 파일 이름을 client로 전송을 하려고 하는데 파일 이름 전송이 끝나고 멈춰버립니다.

두번째 문제..
첫번째 관련 부분을 주석처리하고 돌려봤는데 파일이 오류없이 전송되었나 하는 부분을 파일 사이즈로 체크를 하려고 하는데 client로 전송이되면 이상한 문자가 되어버리는군요..그래서 체크 못하고..

세번째 문제..
한번 전송이 끝나도 client쪽에서 q라는 문자를 입력하기 전까지 계속 돌아가게 하려고 하는데 그게 안되는군요..

소스 올려드립니다. 며칠째 찾고 있는데 문제 해결을 못해서 올립니다.

/*
 * server.c
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> //file size를 알아내기 위한..
#include <dirent.h>  //폴더의 file name를 가지고 오기 위한 헤더 파일
#include <sys/socket.h>

#define BUFSIZE 100

void error_handling(char *message); //에러 메시지 출력을 위한 함수

int main(int argc, char **argv)
{
	DIR *pdir = opendir(".");  //폴더의 파일 이름을 가지고 오기위한..
	struct dirent *pent;
	
	struct stat st;
	
	int serv_sd;
	int clnt_sd;
	char mes[BUFSIZE];
	char file_name[BUFSIZE];
	char buf[BUFSIZE];
	int fd;
	char size[BUFSIZE];
			
	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;
	int clnt_addr_size;
	int len;
	
	if(argc!=2){
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}

	serv_sd=socket(PF_INET, SOCK_STREAM, 0);
	if(serv_sd == -1)
		error_handling("socket() error");

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	serv_addr.sin_port=htons(atoi(argv[1]));

	if(bind(serv_sd, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1)
		error_handling("bind() error");

	if(listen(serv_sd, 5)==-1)
		error_handling("listen() error");

	clnt_addr_size=sizeof(clnt_addr);
	clnt_sd=accept(serv_sd, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

	if(clnt_sd==-1)
		error_handling("accept() error");
		
	printf("현재 폴더의 파일 출력\n");    //현재 폴더의 파일 이름 출력하면서 
	while ( (pent=readdir(pdir)) != '\0' ) {  //client에 보내줌
	printf("%s\n", pent->d_name);
	write(clnt_sd, pent->d_name, BUFSIZE);
	}
	
	closedir(pdir); 
while (1){
	while (1) {
		len=read(clnt_sd, file_name, BUFSIZE);  //client에서 파일 이름 입력받음
		file_name[len]='\0';
		fd=open(file_name, O_RDONLY);  //받은 파일 이름을 열어서
		if(fd==-1) {  //파일이 있으면 있음 메시지를 없으면 없다는 메시지 보냄
			printf("File open error");
			strcpy(mes,"없음");
			write(clnt_sd, mes, strlen(mes));
		}
		else {
			strcpy(mes, "있음");
			write(clnt_sd, mes, strlen(mes));
			break;
		}
	}
	sleep(1); //대기시간
	while((len=read(fd, buf, BUFSIZE))!=0){ //파일 내용을 client에 보내줌
		write(clnt_sd, buf, len);
	}
	
	stat(file_name, &st);
	printf("%ld\n", st.st_size);
	sprintf(size, "%ld", st.st_size);
	write(clnt_sd, size, strlen(size));	
	printf("%s\n", size);	
	
	close(fd);
}
	if(shutdown(clnt_sd, SHUT_WR)==-1) 
		error_handling("shutdown error");

	len=read(clnt_sd, buf, BUFSIZE);
	write(1, buf, len);

	close(clnt_sd);

	return 0;

}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

/*
 * clent.c
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>

#define BUFSIZE 100

void error_handling(char *message);

int main(int argc, char **argv)
{
	int fd;
	int sd;
	
	struct stat st;
	
	char buf[BUFSIZE], d_name[BUFSIZE];
	char mes[BUFSIZE];
	char file_name[BUFSIZE];
	int len;
	char size[BUFSIZE];
	long file_size;
	int file_name12;

	struct sockaddr_in serv_addr;

	if(argc!=3){
		printf("Usage : %s <IP> <port>\n", argv[0]);
		exit(1);
	}

	sd=socket(PF_INET, SOCK_STREAM, 0);
	if(sd == -1)
		error_handling("socket() error");

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
	serv_addr.sin_port=htons(atoi(argv[2]));


	if(connect(sd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)
		error_handling("connect() error!");
	
	printf("공유된 서버 폴더의 파일 이름\n");
	
      while(len=read(sd, d_name, BUFSIZE) !=0 ) {  //server로 부터 받은 파일 이름들 출력
		printf("%s\n", d_name);
	}
	while (1){
			
	while (1){
		printf("받을 파일의 이름을 입력하시오 (종료는 q)"); //받을 파일의 이름 입력 받아서
		scanf("%s", file_name);
	
		if(!strcmp(file_name, "q")) exit (1);  //q를 입력받으면 바로 종료
	
		write(sd, file_name, strlen(file_name));  //server로 전송
	
		len=read(sd, mes, BUFSIZE); //server에서 확인된 미시지 전송받음
		mes[len]='\0';
		if(!strcmp(mes,"있음")) break;  //파일이 있는경우 다음으로..
		else printf("선택한 파일명이 없습니다. 다시 입력해주십시오"); //파일없으면 다시
	}
		
		printf("같은 파일명으로 저장은 1, 다른 파일명으로 저장은 2 : ");
		scanf("%d", &file_name12);
		
		if ( file_name12 == 2){
			printf("저장할 파일명을 입력하시오.");
			scanf("%s", file_name);
		}

		while(1){ //파일 열기
			fd=open(file_name, O_CREAT|O_WRONLY|O_EXCL); 
			if(fd==-1){ //같은 파일 이름이 있을 경우 파일 이름 다시 받아서 열기
				printf("같은 파일명이 폴더내에 존재합니다.\n");
				printf("새로운 파일명을 입력해 주세요\n");
				scanf("%s", file_name);
		}
		else break;  //열기 성공시 다음으로..
	}
	
    while((len=read(sd, buf, BUFSIZE)) !=0) { //server로 부터 파일의 내용 전송받아 
			write(fd, buf, len);
	}

	stat(file_name, &st);
	printf("file %d\n", st.st_size);
	len=read(sd, size, BUFSIZE-1);
	size[len]='\0';
	printf("%s\n", size);
		
	file_size=atol(size);
	printf("file_size %ld\n", file_size);
	
	if ( st.st_size != file_size) {
		close(fd);
		printf("파일 전송 실패!!! 다시 한번 시도해 주십시오\n");
		fd=open(file_name, O_TRUNC);
		close(fd);
		
	}
	close(fd);
	
	}
	write(sd, "Thank you\n", 10);  //server에 thank you메시지 전송

	close(sd);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
marten의 이미지

    while(len=read(sd, d_name, BUFSIZE) !=0 ) {  //server로 부터 받은 파일 이름들 출력 
      printf("%s\n", d_name); 
   } 

read가 0을 리턴하는 경우는 연결이 끊겼을 때입니다. 파일IO로 따지자면 EOF을 만났을 경우죠. 이 경우에는 서버에서 보내준 파일목록을 다 읽고 난 뒤, read()에서 블럭이 되겠네요. 연결이 끊긴 것은 아니기 때문에 while문을 빠져나올 수 없습니다.

댓글 달기

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 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.