Skip to content

Latest commit

 

History

History
141 lines (106 loc) · 4 KB

File metadata and controls

141 lines (106 loc) · 4 KB

16장 입출력 스트림의 분리에 대한 나머지 이야기

16-1 입력 스트림과 출력 스트림의 분리

입출 스트림의 분리

  • 프로세스 기반의 분리 : write용 프로세스, read용 프로세스 fork를 통한 분리
  • FILE 구조체 포인터 기반의 분리 : FILE 구조체를 각각 write와 read로 관리
    • 입력모드과 출력모드의 구분을 통한 구현의 편의성 증대
    • 입력 버퍼와 출력 버퍼를 구분함으로 인한 버퍼링 기능의 향상
	readfp=fdopen(sock, "r");
	writefp=fdopen(sock, "w");

스트림 분리 이후 Half-close의 문제

  • Half-close : EOF를 전달하여 더 이상 보낼 데이터가 없다고 알리고 출력 스트림을 닫아버림
  • fclose를 통해 FILE* 를 닫으면 연결된 파일 디스크립터도 close가 되어버림
  • write에 사용하고 있던 FILE*를 닫으면 read도 제대로 이루어지지 않음
int main(int argc, char *argv[])
{
	FILE * readfp;
	FILE * writefp;
	...;

	readfp=fdopen(sock, "r");
	writefp=fdopen(sock, "w");
	...;

	fclose(writefp);
    	...;
    	fgets(buf, sizoef(buf), readfp);

    	fclose(readfp);
	return 0;
}

서버가 마지막 문자열을 수신하지 못하는 상황 이 일어날 수 잇다.


16-2 파일 디스크립터의 복사와 Half-close

스트림 종료 시 half-close가 되지 않는 이유

int main(int argc, char *argv[])
{
	int sock;
	char message[BUF_SIZE];
	int str_len;
	struct sockaddr_in serv_adr;
	FILE * readfp;
	FILE * writefp;

	sock=socket(PF_INET, SOCK_STREAM, 0);
	...;

	readfp=fdopen(sock, "r");		// fd -> FILE*
	writefp=fdopen(sock, "w");		// fd -> FILE*
}

https://blog.kakaocdn.net/dn/42ywh/btq1bfXiCNx/LfPzm0avCo4NiWqTrwfLHK/img.png

	while(1)
	{
		fputs("Input message(Q to quit): ", stdout);
		fgets(message, BUF_SIZE, stdin);
		if(!strcmp(message,"q\n") || !strcmp(message,"Q\n")) {
			break;
		}

		fputs(message, writefp);		// 전송
		fflush(writefp);				// 버퍼 비움
 		fgets(message, BUF_SIZE, readfp);		// 수신
		printf("Message from server: %s", message);
	}
	fclose(writefp);
	fclose(readfp);
	return 0;
}

https://blog.kakaocdn.net/dn/bt2U1v/btq09yQXPmq/1dvVYUhtKQfBI7ss2cWcy0/img.png

위 문제를 해결하기 위해서 파일 디스크립터를 복사하고 각각에 FILE*를 연결하면 소멸 시 해당 파일 디스크립터만 소멸

https://blog.kakaocdn.net/dn/TgBeg/btq1jmt2cbQ/HjibKtfBaM766HkQ2tY3SK/img.png

파일 디스크립터의 복사

동일한 파일 또는 소켓의 접근을 위한 또 다른 파일 디스크립터의 생성

dup은 복사된 파일 디스크립터 번호가 운영체제에서 주어진다면, dup2는 복사된 파일 디스크립터의 번호를 지정할 수 있다.

#include <unistd.h>

int dup(int fildes);
int dup2(int fildes, int fildes2);
// 성공 시 복사된 파일 디스크립터, 실패 시 -1 반환
// fildes : 복사할 파일 디스크립터 전달
// fildes2 : 명시적으로 지정할 파일 디스크립터의 정수 값 전달
int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;
	FILE * readfp;
	FILE * writefp;

    ...;
	serv_sock=socket(PF_INET, SOCK_STREAM, 0);
	...;

	readfp=fdopen(clnt_sock, "r");
	writefp=fdopen(dup(clnt_sock), "w");		// fd 복사

	fputs("FROM SERVER: Hi~ client? \n", writefp);
	fputs("I love all of the world \n", writefp);
	fputs("You are awesome! \n", writefp);
	fflush(writefp);

	shutdown(fileno(writefp), SHUT_WR);		// half-close
	fclose(writefp);

	fgets(buf, sizeof(buf), readfp); fputs(buf, stdout);
	fclose(readfp);
	return 0;
}

복사된 파일 디스크립터의 수에 상관없이 EOF의 전송을 동반하는 Half-close를 진행하기 위해서는 shutdown 함수를 호출해야 한다.