IT_Programming/Network Programming

[Winsock] TCP_IP Half Close를 이용한 파일전송

JJun ™ 2009. 7. 2. 09:26

==================================================================================================

간단한 파일 전송 구현 ...

서버가 소켓을 완전 종료(close/closesocket) 하면서 EOF를 전송하게 되면, 클라이언트로부터 데이터를

수신 받지 못한다. EOF도 보내고, 데이터도 수신할 수 있는 상태가 되게 하기 위해 Half-Close를 사용한다.

==================================================================================================

 

[실행화면]

 

 

 

 

- receive.dat

 

==================================================================================================

 

[소스코드]

 

- server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

 

#pragma comment(lib, "ws2_32.lib") // winsock2를 사용하기 위함

 

#define BUF_SIZE 1024

 

void dll_load(WSADATA *wsaData);
void conn_init(SOCKET *serv_sock, SOCKADDR_IN *serv_addr, int port);
void accept_client(SOCKET *clnt_sock, SOCKET *serv_sock, SOCKADDR_IN *clnt_addr, int *size);
void conn_finish(SOCKET *clnt_sock);
void ErrorHandling(char *message);

 

int main(int argc, char *argv[])
{
     WSADATA wsaData;
     SOCKET hServSock, hClntSock;
     SOCKADDR_IN serv_addr, clnt_addr;
     FILE *fp;
     char message[BUF_SIZE];
     int clntAddrSize, len;
 
     if(argc != 2)
     {
          printf("Usage : %s <PORT>", argv[0]);
          exit(0);
     }
 
     dll_load(&wsaData);
     memset(&serv_addr, 0, sizeof(serv_addr));
     conn_init(&hServSock, &serv_addr, atoi(argv[1]));
 
     fp = fopen("endian_conv.c", "r");
    

     if(fp == NULL)
          ErrorHandling("File open Error");

 

     if(bind(hServSock, (SOCKADDR *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR)
          ErrorHandling("bind() Error!");

 

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

 

     clntAddrSize = sizeof(clnt_addr);
     accept_client(&hClntSock, &hServSock, &clnt_addr, &clntAddrSize);

 

     while(1)
     {
          len = fread(message, sizeof(char), BUF_SIZE, fp);
          send(hClntSock, message, len, 0);

 

          if(feof(fp))
               break;
     }

 

     if(shutdown(hClntSock, SD_SEND) == SOCKET_ERROR) // Half Close
          ErrorHandling("shutdown() Error!");

 

     len = recv(hClntSock, message, BUF_SIZE-1, 0);
     message[len] = 0;
     fputs(message, stdout);

    

     fclose(fp);
     conn_finish(&hClntSock);
 
     return 0;
}

 

void dll_load(WSADATA *wsaData) // Winsock 2.2 dll Load
{
     if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0)
          ErrorHandling("WSAStartup() Error!");
}

 

// 네트워크 초기 세팅
void conn_init(SOCKET *serv_sock, SOCKADDR_IN *serv_addr, int port)
{
     *serv_sock = socket(PF_INET, SOCK_STREAM, 0);

     if(*serv_sock == INVALID_SOCKET)
          ErrorHandling("socket() Error!");

 

     serv_addr->sin_family = AF_INET;
     serv_addr->sin_addr.s_addr = htonl(INADDR_ANY);
     serv_addr->sin_port = htons(port);
}

 

// 클라이언트의 접속을 처리
void accept_client(SOCKET *clnt_sock, SOCKET *serv_sock, SOCKADDR_IN *clnt_addr, int *size)
{
     *clnt_sock = accept(*serv_sock, (SOCKADDR *)clnt_addr, size);
     if(*clnt_sock == INVALID_SOCKET)
          ErrorHandling("accept() Error!");

}

 

// 네트워크 연결 종료
void conn_finish(SOCKET *clnt_sock)
{
     closesocket(*clnt_sock);
     WSACleanup();
}

 

// 에러 처리 함수

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

 

-----------------------------------------------------------------------------------------------

 

- client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

 

#pragma comment(lib, "ws2_32.lib") // winsock2를 사용하기 위함

 

#define BUF_SIZE 1024

 

void dll_load(WSADATA *wsaData);
void conn_init(SOCKET *sock, SOCKADDR_IN *serv_addr, char *IP_Address, int port);
void conn_finish(SOCKET *sock);
void ErrorHandling(char *message);

 

int main(int argc, char *argv[])
{
     WSADATA wsaData;
     SOCKET sock;
     SOCKADDR_IN serv_addr;
     FILE *fp;
     char message[BUF_SIZE];
     int len;
 
     if(argc != 3)
     {
          printf("Usage : %s <IP> <PORT>\n", argv[0]);
          exit(0);
     }

 

     dll_load(&wsaData);
     memset(&serv_addr, 0, sizeof(serv_addr));
     conn_init(&sock, &serv_addr, argv[1], atoi(argv[2]));

 

     if(connect(sock, (SOCKADDR *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR)
          ErrorHandling("connect() Error!");
 
     if((fp = fopen("./receive.dat", "w")) == NULL)
          ErrorHandling("File Open failed!");

 

     while((len = recv(sock, message, BUF_SIZE, 0)) != 0)
          fwrite(message, sizeof(char), len, fp);
  
     send(sock, "Thank you\n", 10, 0);
 
     fclose(fp);
     conn_finish(&sock);
 
     return 0;
}

 

void dll_load(WSADATA *wsaData) // Winsock 2.2 dll Load
{
     if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0)
          ErrorHandling("WSAStartup Error!");
}

 

// 네트워크 초기 세팅
void conn_init(SOCKET *sock, SOCKADDR_IN *serv_addr, char *IP_Address, int port)
{
     *sock = socket(PF_INET, SOCK_STREAM, 0);
     if(*sock == INVALID_SOCKET)
          ErrorHandling("socket() Error!");

 

     serv_addr->sin_family = AF_INET;
     serv_addr->sin_addr.s_addr = inet_addr(IP_Address);
     serv_addr->sin_port = htons(port);
}

 

// 네트워크 연결 종료
void conn_finish(SOCKET *sock)
{
     closesocket(*sock);
     WSACleanup();
}

 

// 에러 처리 함수
void ErrorHandling(char *message)
{
     fputs(message, stderr);
     fputc('\n', stderr);
     exit(1);
}

 

==================================================================================================