더보기
Part 01
Ch. 01. Socket Network Programming
Ch. 02. File Descriptor, open(), close(), write(), read()
Ch. 05. Network Byte Order, Big Endian, Little Endian
Part 2
Ch.10.
Ch.11.
Ch.12.
Ch.13.
Ch.14.
Ch.15.
Ch.16.
Ch.17.
Ch.18.
1. 일방적인 연결 종료의 문제점
호스트 A - 데이터 전송 후 close() 함수를 통해 연결 종료
호스트 B - 데이터 수신 후 호스트 A 에게 송신
호스트 A - 반드시 수신해야 할 데이터 소멸
2. 스트림
소켓의 연결을 통해 데이터 송수신이 가능한 상태를 "스트림이 형성된 상태"라 한다.
양방향 통신을 위해서는 두개의 스트림이 필요하다.
두 호스트 간에 소켓이 연결되면, 각 호스트 별로 입력, 출력 스트림이 형성된다.
한 호스트의 입력 스트림은 상대 호스트의 출력 스트림으로 이어지고, 상대의 출력 스트림은 다른 호스트의 입력 스트림으로 연결된다.
3. shutdown()
#include <sys/socket.h>
int shutdown(int sock, int howto);
// 성공시 0 , 실패시 -1 반환
// sock 종료 할 소켓의 파일 디스크립터 전달.
// howto 종료 방법에 대한 정보 전달.
SHUT RD : 입력 스트림 종료
SHUT WR : 출력 스트림 종료
SHUT RDWR : 입출력 스트림 종료
4. Half-close 가 필요한 이유
Server는 클라이언트의 요청에 대한 전송 실행 후, 연결을 끊을 수 있지만, Client의 경우 언제가지 데이터를 수신해야 할지 알 수 없다.
따라서 Client는 EOF의 수신을 통해 종료를 확인한다.
Server가 마지막 "Thank You"를 수신하기 위해 Half-close를 사용한다.
// Server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int serv_sd, clnt_sd;
FILE * fp;
char buf[BUF_SIZE];
int read_cnt;
struct sockaddr_in serv_adr, clnt_adr;
socklen_t clnt_adr_sz;
if(argc!=2) {
printf("Usage: %s <port>\n", argv[0]);
exit(1);
}
fp=fopen("file_server.c", "rb");
serv_sd=socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_adr.sin_port=htons(atoi(argv[1]));
bind(serv_sd, (struct sockaddr*)&serv_adr, sizeof(serv_adr));
listen(serv_sd, 5);
clnt_adr_sz=sizeof(clnt_adr);
clnt_sd=accept(serv_sd, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
while(1)
{
read_cnt=fread((void*)buf, 1, BUF_SIZE, fp);
if(read_cnt<BUF_SIZE)
{
write(clnt_sd, buf, read_cnt);
break;
}
write(clnt_sd, buf, BUF_SIZE);
}
shutdown(clnt_sd, SHUT_WR);
read(clnt_sd, buf, BUF_SIZE);
printf("Message from client: %s \n", buf);
fclose(fp);
close(clnt_sd); close(serv_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 <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int sd;
FILE *fp;
char buf[BUF_SIZE];
int read_cnt;
struct sockaddr_in serv_adr;
if(argc!=3) {
printf("Usage: %s <IP> <port>\n", argv[0]);
exit(1);
}
fp=fopen("receive.dat", "wb");
sd=socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
serv_adr.sin_port=htons(atoi(argv[2]));
connect(sd, (struct sockaddr*)&serv_adr, sizeof(serv_adr));
while((read_cnt=read(sd, buf, BUF_SIZE ))!=0)
fwrite((void*)buf, 1, read_cnt, fp);
puts("Received file data");
write(sd, "Thank you", 10);
fclose(fp);
close(sd);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}