현생/TCP 소켓 프로그래밍

10-7 TCP의 입출력 루틴 분할 [TCP/IP][C][LINUX]

푸더기 2022. 1. 30. 14:32
반응형

 

이 글에는 멀티프로세스 생성 방법에 대한 설명 없이 응용만 합니다.
따라서 멀티프로세스 생성 방법 등은 아래를 참고해주세요.
https://pupuduck.tistory.com/63
https://pupuduck.tistory.com/66

 

 

 

지금까지 구현한 에코 클라이언트의 입출력 방식은 입력 -> 데이터가 수신되길 계속 기다림 -> 수신되면 출력 을 반복해왔습니다. 만약 데이터가 수신되지 않는다면 더 이상 입력은 하지 못합니다.

 

따라서 입출력 루틴을 분할하게 되면 데이터 수신여부와 관계없이 입력을 할 수 있습니다. 또, 입력부와 출력부를 따로 구현할 수 있는 편의성을 갖게 되고, 데이터 송수신이 잦은 프로그램의 성능이 향상됩니다. 송수신 시간을 기다리지 않아, 동일한 시간 내 데이터 송수신 분량이 많아지기 때문입니다.

 

다음 소스코드는 입출력 루틴을 분할한 에코 클라이언트입니다.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUF_SIZE 1024

void error_handling(char *message);
void read_routine(int sock, char *buf);
void write_routine(int sock, char *buf);

int main(int argc, char *argv[]){
	int sock;
	pid_t pid;
	char buf[BUF_SIZE];
	struct sockaddr_in serv_adr;
	
	if(argc!=3){
		printf("Usage : %s <IP> <port>\n",argv[0]);
		exit(1);
	}
	sock=socket(PF_INET,SOCK_STREAM,0);
	if(sock==-1)
		error_handling("socket() error");
	
	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]));
	
	if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
		error_handling("connect() error");
	
	pid=fork();
	if(pid==0)
		write_routine(sock, buf);
	else
		read_routine(sock, buf);

	close(sock);
	return 0;
}

void read_routine(int sock, char *buf){
	while(1){
		int str_len=read(sock,buf,BUF_SIZE);
		if(str_len==0) 
			return;
		
		buf[str_len]=0;
		printf("Messsage from server: %s",buf);
	}	
}

void write_routine(int sock, char *buf){
	while(1){
		fgets(buf,BUF_SIZE,stdin);
		if(!strcmp(buf,"q\n") || !strcmp(buf,"Q\n")){
			shutdown(sock, SHUT_WR);
			return;
		}
		write(sock, buf, strlen(buf));
	}
}

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

서버는 직전에 멀티프로세스기반 다중접속 에코서버를 사용 하면 됩니다. https://pupuduck.tistory.com/69에 있습니다.

 

write_routine에서 shutdown 함수를 호출했는데, 물론 close 함수 호출을 통해 EOF의 전달을 기대할 수 있지만 파일 디스크립터가 복사된 상황이므로 한번의 close 함수 호출을 통해 EOF의 전달을 기대할 수 없습니다. 따라서 shutdown 함수의 호출을 통해 EOF의 전달을 별도로 명시해야 합니다.

 

shutdown 함수에 대한 글은 여기를 봐주세요. https://pupuduck.tistory.com/40

반응형