HALF-CLOSE 의 필요성
서버로부터 파일 수신이 끝나면 그 다음에는 클라이언트가 데이터를 전송해야만 하는 상황이 되는데 이러한경우에는 서버가 반드시 half-close를 해야 한다.
그렇지 않으면 클라이언트는 어느 시점에서 데이터를 수신을 종료하고, 서버로의 데이터 전송을 시작할 것인지를 알지 못한다.
그렇다고 서버가 소켓을 완전종료(close function call) 하면서 EOF를 전송하게 되면 클라이언트로 부터 데이터를 수신받지 못한다. EOF도 보내고 데이터를 수신할 수 있는 상태가 되려면 어떻게 해야 하는가 당연히 half-close이다.
///////////////////////////////////////////////////// Server
#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>
#define BUFSIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int serv_sd;
int clnt_sd;
int fd;
char buf[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);
}
fd = open("file_server.c", O_RDONLY);
if(fd == -1)
error_handling("file open error");
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");
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");
while((len = read(fd, buf, BUFSIZE)) != 0)
{
write(clnt_sd, buf, len);
}
//
// 데이터 전송후 일부(전송영역)을 닫음
// Half-close 해주는 것
// 클라이언트에게 EOF를 주어 파일 전송이 마무리 되었다는 것을 알린다.
//
if(shutdown(clnt_sd, SHUT_WR) == -1)
error_handling("shutdown error");
//
// 최종 메시지를 받기위해 read함수를 호출한다.
//
len = read(clnt_sd, buf, BUFSIZE);
write(1, buf, len);
close(fd);
close(clnt_sd);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
/////////////////////////////////////////////////////// Client
#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>
#define BUFSIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int fd;
int sd;
char buf[BUFSIZE];
int len;
struct sockaddr_in serv_addr;
if(argc != 3)
{
printf("Usage : %s <IP> <port> \n", argv[0]);
exit(1);
}
fd = open("recevice.dat", O_WRONLY | O_CREAT | O_TRUNC);
if(fd == -1)
error_handling("File open error");
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!");
//
// EOF를 받을 때까지 계속된다.
//
while((len == read(sd, buf, BUFSIZE)) != 0)
{
write(fd, buf, len);
}
//
// 파일을 끝까지 받았다는 것을 알린다.
//
write(sd, "Thank you\n", 10);
close(fd);
close(sd);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
서버로부터 파일 수신이 끝나면 그 다음에는 클라이언트가 데이터를 전송해야만 하는 상황이 되는데 이러한경우에는 서버가 반드시 half-close를 해야 한다.
그렇지 않으면 클라이언트는 어느 시점에서 데이터를 수신을 종료하고, 서버로의 데이터 전송을 시작할 것인지를 알지 못한다.
그렇다고 서버가 소켓을 완전종료(close function call) 하면서 EOF를 전송하게 되면 클라이언트로 부터 데이터를 수신받지 못한다. EOF도 보내고 데이터를 수신할 수 있는 상태가 되려면 어떻게 해야 하는가 당연히 half-close이다.
///////////////////////////////////////////////////// Server
#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>
#define BUFSIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int serv_sd;
int clnt_sd;
int fd;
char buf[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);
}
fd = open("file_server.c", O_RDONLY);
if(fd == -1)
error_handling("file open error");
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");
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");
while((len = read(fd, buf, BUFSIZE)) != 0)
{
write(clnt_sd, buf, len);
}
//
// 데이터 전송후 일부(전송영역)을 닫음
// Half-close 해주는 것
// 클라이언트에게 EOF를 주어 파일 전송이 마무리 되었다는 것을 알린다.
//
if(shutdown(clnt_sd, SHUT_WR) == -1)
error_handling("shutdown error");
//
// 최종 메시지를 받기위해 read함수를 호출한다.
//
len = read(clnt_sd, buf, BUFSIZE);
write(1, buf, len);
close(fd);
close(clnt_sd);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
/////////////////////////////////////////////////////// Client
#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>
#define BUFSIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int fd;
int sd;
char buf[BUFSIZE];
int len;
struct sockaddr_in serv_addr;
if(argc != 3)
{
printf("Usage : %s <IP> <port> \n", argv[0]);
exit(1);
}
fd = open("recevice.dat", O_WRONLY | O_CREAT | O_TRUNC);
if(fd == -1)
error_handling("File open error");
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!");
//
// EOF를 받을 때까지 계속된다.
//
while((len == read(sd, buf, BUFSIZE)) != 0)
{
write(fd, buf, len);
}
//
// 파일을 끝까지 받았다는 것을 알린다.
//
write(sd, "Thank you\n", 10);
close(fd);
close(sd);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
'Etc > TCP/IP' 카테고리의 다른 글
ip 주소를 이용해서 도메인 이름 알아내기 (0) | 2013.09.25 |
---|---|
도메인 이름을 이용해서 ip주소 얻어내기 (0) | 2013.09.25 |
UDP 기반의 데이터 입,출력 함수 (0) | 2013.09.25 |
UDP 기반의 데이터 입,출력 함수 (0) | 2013.09.25 |
UDP 기반의 ECHO서버/클라이언트 (0) | 2013.09.25 |