소켓통신 초보자인데,, 파일 전송이 이상하게 이루어집니다.

youdotan의 이미지

안녕하세요.
최근 필요에 의해 소켓통신을 공부하기 시작했는데
간단(?)하게 파일 송수신 기능을 해보려는데.. 잘 안되네요.

현상은 a.txt라는 파일을 송신하면, server가 이를 받는 소스를 구현한건데..
recv의 return이 항상 1이 나와서 server에서 받은 파일에 txt 내용이 많이 빠져있습니다.
send return 값은 분명 의도한대로 30인데 server 부분이 항상 1만 처리하네요..
즉, 1234567890123456789012345678901234567890123456789091234567890.....이런 텍스트를 보내면 30번째 자리 텍스트만 남아서
1111.. 이런 식으로 수신 부에서 파일이 만들어집니다.

소스파일을 올려봅니다(main만..). 물론 이 외에도 문제가 많은 소스지만..ㅎ
질문에 대해 도와주시면 감사하겠습니다 ^^

<서버> #define MAX_PATH 256 #include "stdafx.h"

int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hServSock, hClntSock;
SOCKADDR_IN servAddr, clntAddr;

FILE *file;

char File_Name[MAX_PATH];
int File_Name_len;
char Data[30];
int Data_len;
int szClntAddr;
char message[]="Hello World!";

if(argc!=2)
{
printf("Usage : %s \n", argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0)
ErrorHandling("WSAStartup() error!");

hServSock=socket(PF_INET, SOCK_STREAM, 0);
if(hServSock==INVALID_SOCKET)
ErrorHandling("socket() error");

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

if(bind(hServSock, (SOCKADDR*) &servAddr, sizeof(servAddr))==SOCKET_ERROR)
ErrorHandling("bind() error");

if(listen(hServSock, 5)==SOCKET_ERROR)
ErrorHandling("listen() error");

while(1)
{
szClntAddr=sizeof(clntAddr);
hClntSock=accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr);
if(hClntSock==INVALID_SOCKET)
ErrorHandling("accept() error");

//send(hClntSock, message, sizeof(message), 0);
while(1)
{
File_Name_len = recv(hClntSock, File_Name, MAX_PATH, 0);
if(File_Name_len==-1)
{
break;
}
strcpy(File_Name, "b.txt");
file = fopen(File_Name, "w+");

Sleep(100);

while (Data_len = recv(hClntSock, Data, 30, 0) != 0)
{
fwrite(Data, sizeof(char), Data_len, file);
}

fclose(file);
}
}

closesocket(hClntSock);
closesocket(hServSock);
WSACleanup();
return 0;
}

<클라이언트>

#define MAX_PATH 256
#include "stdafx.h"

void ErrorHandling(char* message);

int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hSocket;
SOCKADDR_IN servAddr;

//char message[30];
FILE *file;
int File_len;

int strLen;
char message[]="Hello World!";
char File_Path[MAX_PATH];
char File_Name[MAX_PATH];
char buf[30];
int tmp;

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

if(WSAStartup(MAKEWORD(2, 2), &wsaData) !=0)
ErrorHandling("WSAStartup() errer!");

hSocket=socket(PF_INET, SOCK_STREAM, 0);
if(hSocket==INVALID_SOCKET)
ErrorHandling("hSocketet() error!");

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

if(connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr))==SOCKET_ERROR)
ErrorHandling("connect() error!");

while(1)
{
char *p = NULL;

printf("File Name to Server: ");
scanf("%s", File_Path);
p = strrchr(File_Path, '/');
strcpy(File_Name, p+1);

if (!strcmp(File_Path, "exit"))
return 0;

file = fopen(File_Path, "r");
if (!file)
ErrorHandling("fopen() error!\n");

while(1)
{
File_len = fread(buf, sizeof(char), 30, file);
tmp = send(hSocket, buf, File_len, 0);
if(feof(file))
{
printf("끗\n");
break;
}
}

if(shutdown(hSocket, SD_SEND) == SOCKET_ERROR)
ErrorHandling("shutdown() error!");

fclose(file);
}

closesocket(hSocket);
WSACleanup();
return 0;
}

mirheekl의 이미지

1. 파일명을 클라이언트에서 받아오는것 같은데 파일명과 실제 데이터를 뚜렷이 구분할 방법이 없는듯 합니다. 어차피 해당 파일명을 사용하지도 않는걸로 봐서 개발중이신듯 한데, 데이터 송수신이 제대로 되는걸 확인후 다시 넣으시면 좋지 않을까 합니다. 즉 파일명 받아오는 부분을 빼고 먼저 시도해보세요. 그리고 저런건 프로토콜 처리를 하는게 좋습니다. 지금 상태로는 파일명 뒤에 실제 데이터가 다닥다닥 붙어 들어와서 처음 리시브에서 한꺼번에 다 읽어버리면 데이터가 날아가게 구현되어 있네요.

2. 루프를 돌면서 수신을 하는 부분이 에러처리가 제대로 안돼있는듯 합니다. recv의 리턴값은 크게 세 종류입니다. 수신성공-소켓종료-에러..

3. 보아하니 코드상으론 블로킹 처리를 하게 되어있는데 블로킹 모드가 제대로 활성화되어있는지 확인해보세요.

--

zalhae의 이미지

원인은 서버쪽에 파일 이름을 수신한 후에
while (Data_len = recv(hClntSock, Data, 30, 0) != 0)
라고 되어 있는 부분에 문제가 있기 때문입니다.

Data_len = recv(hClntSock, Data, 30, 0);
로 동작하는 것이
아니라
Data_len = (recv(hClntSock, Data, 30, 0) != 0);
로 동작하여 Data_len은 통신이 이상하지 않는 한 1로 반환되기 때문에 문의하신 상황과 동일하게 1로만 기록된 것입니다.

따라서
while ( (Data_len = recv(hClntSock, Data, 30, 0)) != 0)
와 같이 괄호를 잘 묶어서 다시 확인해 보시면 일단 동작을 잘 될 것입니다.

좀더 쉽게 설명하면 아래 코드에서 func()의 결과는 무조건 3이 나가지만 님이 코딩한 스타일대로 동작한다면 결과는 항상 1로 반환되는 것과 같은 이치입니다.
#include

int func()
{
return 3;
}

int main(int argc, char **argv)
{
int i;

while ( i = func() != 0 )
{
printf(" i= %d\n", i);
return 0;
}

return 0;
}

# ./a
i= 1
i= 1
i= 1
생략

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.