소켓통신 초보자인데,, 파일 전송이 이상하게 이루어집니다.
안녕하세요.
최근 필요에 의해 소켓통신을 공부하기 시작했는데
간단(?)하게 파일 송수신 기능을 해보려는데.. 잘 안되네요.
현상은 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;
}
간단한것 몇가지..
1. 파일명을 클라이언트에서 받아오는것 같은데 파일명과 실제 데이터를 뚜렷이 구분할 방법이 없는듯 합니다. 어차피 해당 파일명을 사용하지도 않는걸로 봐서 개발중이신듯 한데, 데이터 송수신이 제대로 되는걸 확인후 다시 넣으시면 좋지 않을까 합니다. 즉 파일명 받아오는 부분을 빼고 먼저 시도해보세요. 그리고 저런건 프로토콜 처리를 하는게 좋습니다. 지금 상태로는 파일명 뒤에 실제 데이터가 다닥다닥 붙어 들어와서 처음 리시브에서 한꺼번에 다 읽어버리면 데이터가 날아가게 구현되어 있네요.
2. 루프를 돌면서 수신을 하는 부분이 에러처리가 제대로 안돼있는듯 합니다. recv의 리턴값은 크게 세 종류입니다. 수신성공-소켓종료-에러..
3. 보아하니 코드상으론 블로킹 처리를 하게 되어있는데 블로킹 모드가 제대로 활성화되어있는지 확인해보세요.
--
원인은 서버쪽에 파일 이름을 수신한 후에 while
원인은 서버쪽에 파일 이름을 수신한 후에
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
생략
댓글 달기