9. 다양한 입출력 함수들

2024. 9. 3. 18:41·스터디/TCP 와 IP
728x90
반응형

send & recv 입출력 함수

리눅스 기반에서 send & recv 함수를 소개하겠다.
이는 window에서의 함수와 똑같다.

 

 

send

#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);

// 성공 시 전송된 바이트 수, 실패 시 -1 반환

/*
sockfd : 데이터 전송 대상과의 연결을 의미하는 소켓의 파일 디스크립터 전달
buf : 전송할 데이터를 저장하고 있는 버퍼의 주소 값 전달
nbytes : 전송할 바이트 수 전달
flags : 데이터 전송 시 적용할 다양한 옵션 정보 전달
*/

 

recv

#include <sys/socket.h>

ssize_t recv(int sockfd, const void * buf, size_t nbytes, int flags);

//성공 시 수신한 바이트 수(단 EOF 전송 시 0), 실패 시 -1 반환

/*
sockfd : 데이터 수신 대상과의 연결을 의미하는 소켓의 파일 디스크립터 전달
buf : 수신된 데이터를 저장할 버퍼의 주소 값 전달
nbytes : 수신할 수 있는 최대 바이트 수 전달
flasg : 데이터 수신 시 적용할 다양한 옵션 정보 전달
*/

 

윈도우와 선언된 자료형의 이름만 다를 뿐 나머지는 완전히 동일하다.
send와 recv 함수의 마지막 매개변수에는 데이터 송수신시 적용할 옵션정보가 전달된다.
그런데 옵션정보는 비트 OR 연산자(| 연산자)를 이용해서 둘 이상을 함께 전달할 수 있다.
다음은 매개변수에 전달할 수 있는 옵션의 정보와 그 의미이다

 

옵션 의미 send recv
MSG_OOB 긴급 데이터(Out -of - band data) 의 전송을 위한 옵션 ● ●
MSG_PEEK 입력 버퍼에 수신된 데이터의 존재유무 확인을 위한 옵션   ●
MSG_DONTROUTE 데이터 전송과정에서 라우팅(Routing) 테이블을 참조하지 않을 것을 요구하는 옵션 따라서 로컬(Local) 네트워크상에서 목적지를 찾을 때 사용되는 옵션. ●  
MSG_DONTWAIT 입출력 함수 호출 과정에서 블로킹 되지 않을 것을 요구하기 위한 옵션, 즉 넌-블로킹(Non-blocking) IO의 요구에 사용되는 옵션 ● ●
MSG_WAITALL 요청한 바이트 수에 해당하는 데이터가 전부 수신될 때까지 호출된 함수가 반환되는 것을 막기 위한 옵션   ●

 

MSG_OOB : 긴급 메시지의 전송

 

옵션 MSG_OOB는 'Out-of-band data'라 불리는 긴급 메시지의 전송에 사용된다.
간단하게 응급실을 생각해보자.
응급환자가 발생시에 기존에 대기하고 있는 환자들에게 양해를 구하고 먼저 진료를 봐야한다.
이러한 문제점 때문에 응급실이 별도로 존재한다.

 

 

readv & writev 입출력 함수

readv & writev 함수의 기능을 한 마디로 정리하자면 다음과 같다.
"데이터를 모아서 전송하고, 모아서 수신하는 기능의 함수"
즉, writev 함수를 사용하면 여러 버퍼에 나뉘어 있는 데이터를 한 번에 전송할 수 있고,
readv 함수를 사용하면 데이터를 여러 버퍼에 나눠서 수신할 수 있다.
이렇게 사용을 한다면 입출력 함수 호출의 수를 줄일 수 있다.

 

 

writev

 

#include <sys/uio.h>

ssize_t writev(int fildes, const struct iovec * iov, int iovcnt);
// 성공 시 전송된 바이트 수, 실패 시 -1 반환

/*
filedes : 데이터 전송의 목적지를 나타내는 소켓의 파일 디스크립터 전달.
		  단, 소켓에만 제한된 함수가 아니기 때문에, read함수처럼 파일이나 콘솔 대상의 파일 디스크립터도 전달
iov : 구조체 iovec 배열의 주소 값 전달, 구조체 iovec의 변수에는 전송할 데이터의 위치 및 크기 정보가 담긴다.
iovcnt : 두 번째 인자로 전달된 주소 값이 가리키는 배열의 길이 정보 전달
*/

 

다음과 같이 그림으로 쉽게 알아볼 수 있다.

 

위 그림에서 writev의 첫 번째 인자 1은 파일 디스크립터를 의미하므로 콘솔에 출력이 이뤄지고 ptr은 전송할 데이터 정보를 모아둔 iovec 배열을 가리키는 포인터이다. 또한 세 번째 인자가 2이기 때문에 ptr이 가리키는 주소를 시작으로 총 두 개의 iovec 변수를 참조하여 그 두 변수가 가리키는 버퍼에 저장된 데이터의 전송이 진행된다.

 

위그림의 iovec 구조체 배열을 자세히 관찰해보면 ptr[0]의 (배열 첫번 째 요소의) iov_base는 A로 시작하는 문자열을 가리키면서,

iov_len이 3이므로 ABC가 전송된다. 그리고 ptr[1]의 (배열 두번 째 요소의) iov_base는 숫자 1을 가리키며 iov_len이 4이므로 1234가 이어서 전송된다.

 

여기서 writev의 첫 번째 매개 변수 1이 콘솔에 출력이 이뤄진다는 것은
fd = 0 은 standard input이고
fd = 1 은 standard output 이기 때문이다.

 

 

writev 함수의 사용방법과 특성을 확인했으니 이제 예제를 통해 함수를 사용해 보겠다.

#include <stdio.h>
#include <sys/uio.h>

int main(int argc, char *argv[])
{
	struct iovec vec[2];
	char buf1[]="ABCDEFG";
	char buf2[]="1234567";
	int str_len;

	vec[0].iov_base=buf1;
	vec[0].iov_len=3;
	vec[1].iov_base=buf2;
	vec[1].iov_len=4;
	
	str_len=writev(1, vec, 2);
	puts("");
	printf("Write bytes: %d \n", str_len);
	return 0;
}
	vec[0].iov_base=buf1;
	vec[0].iov_len=3;

첫 번째로 전송할 데이터가 저장된 위치와 크기정보를 담고 있다.

 

	vec[1].iov_base=buf2;
	vec[1].iov_len=4;

두 번째로 전송할 데이터가 저장된 위치와 크기정보를 담고 있다.

 

	str_len=writev(1, vec, 2);

 writev 함수의 첫 번째 전달인자가 1이므로 콘솔로 출력이 이뤄진다.

 

 

 

readv

 

#include <sys/uio.h>

ssize_t readv(int fildes, const struct iovec * iov, int iovcnt);
// 성공 시 수신된 바이트 수, 실패 시 -1 반환

/*
filedes : 데이터를 수신할 파일(혹은 소켓)의 파일 디스크립터도 인자로 전달
iov : 데이터를 저장할 위치와 크기 정보를 담고 있는 iovec 구조체 배열의 주소 값 전달
iovcnt : 두 번째 인자로 전달된 주소 값이 가리키는 배열의 길이 정보 전달
*/

 

readv 함수는 writev 함수를 반대로 생각하면 되니 자세한 설명은 넘어가고 바로 코드를 작성해보자.

 

#include <stdio.h>
#include <sys/uio.h>
#define BUF_SIZE 100

int main(int argc, char *argv[])
{
	struct iovec vec[2];
	char buf1[BUF_SIZE]={0,};
	char buf2[BUF_SIZE]={0,};
	int str_len;

	vec[0].iov_base=buf1;
	vec[0].iov_len=5;
	vec[1].iov_base=buf2;
	vec[1].iov_len=BUF_SIZE;

	str_len=readv(0, vec, 2);
	printf("Read bytes: %d \n", str_len);
	printf("First message: %s \n", buf1);
	printf("Second message: %s \n", buf2);
	return 0;
}

/*
swyoon@my_linux:~/tcpip$ gcc readv.c -o rv
swyoon@my_linux:~/tcpip$ ./rv
I like TCP/IP socket programming~
Read bytes: 34 
First message: I lik 
Second message: e TCP/IP socket programming~
*/

 

	vec[0].iov_base=buf1;
	vec[0].iov_len=5;

첫 번째 데이터 저장소의 위치와 저장할 데이터의 크기정보를 설정하고 있다. 특히 저장할 데이터의 크기를 5로 지정했기 때문에

buf1의 크기에 상관없이 최대 5바이트만이 영역에 저장된다.

 

	vec[1].iov_base=buf2;
	vec[1].iov_len=BUF_SIZE;

vec[0]에 등록되어있는 버퍼에 5바이트가 저장되고, 나머지 데이터는 vec[1]에 등록되어있는 버퍼에 저장된다.

특히 구조체 iovec의 멤버 iov_len에는 버퍼에 저장할 최대 바이트 크기 정보를 저장해야한다.

 

	str_len=readv(0, vec, 2);

readv 함수의 첫 번째 전달인자가 0이기 때문에 콘솔로부터 데이터를 수신한다.

 

 

 

readv & writev 함수의 적절한 사용

 

그렇다면 어떤 상황이 readv와 writev 함수를 사용하기에 적절한 것일까 ?
사용할 수 있는 모든 경우가 적절한 상황이다.

 

예를 들어 전송해야 할 데이터가 여러 개의 버퍼(배열)에 나눠어 있는 경우, 모든 데이터의 전송을 위해서는 여러 번의 write 함수를 호출해야 한다. 하지만 이를 한 번의 write 함수 호출로 대신할 수 있다면 당연히 효율적이지 않은가 ?

마찬가지로 readv 함수 또한 여러 번 read 함수를 호출하는 것보다 한 번 호출하는 것이 더 효율적이다.

C언어 차원으로 생각해봐도 함수의 호출 횟수가 적으면, 그만큼 성능이 향상된다는 것을 알 수 있다.
그러나 일반적으로 전송되는 패킷의 수를 줄일 수 있다는 데에 더 큰 의미가 있다.

 

 


전송해야 할 데이터가 세 개의 공간으로 나뉘어 저장된 상황에서 데이터 전송을 예로 들고 있다.
이 상황에서 write 함수를 사용한다면 3번의 호출이 필요할 것이다.

반면 writev 함수를 사용한다면 한 번에 모든 데이터를 출력 버퍼로 밀어 넣고 하나의 패킷만 생성되어서 전송될 확률이 높다.
이는 전송속도의 향상으로 이어질 수 있다.

사진의 오른쪽 부분을 보면 알겠지만 하나의 큰 배열에 3개의 데이터를 모두 옮겨놓고 write 함수를 사용하는 것과 writev 함수를 호출하는 것과 결과는 같다.


하지만 어떤 것이 더 편할지는 누가봐도 알 것이라고 생각한다.
writev 함수와 readv 함수를 사용할 상황이 나오면 적극적으로 사용해야한다.

728x90
반응형

'스터디 > TCP 와 IP' 카테고리의 다른 글

11. 입출력 스트림의 분리에 대한 나머지 이야기  (0) 2024.09.04
10. 소켓과 표준 입출력  (0) 2024.09.04
8. 멀티프로세스 기반의 서버구현  (0) 2024.09.03
7. 도메인 이름과 인터넷 주소  (0) 2024.09.03
6. 소켓의 우아한 연결 종료  (0) 2024.09.03
'스터디/TCP 와 IP' 카테고리의 다른 글
  • 11. 입출력 스트림의 분리에 대한 나머지 이야기
  • 10. 소켓과 표준 입출력
  • 8. 멀티프로세스 기반의 서버구현
  • 7. 도메인 이름과 인터넷 주소
DDD Developer
DDD Developer
  • DDD Developer
    DDD
    DDD Developer
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 개발 일지
        • C언어
        • python 파이썬
        • 기타
        • 데이터베이스
        • TCP 와 IP
        • C++
        • QT
        • C#
      • 스터디
        • C언어
        • python 파이썬
        • TCP 와 IP
        • C++ 스터디
        • QT 스터디
      • 프로젝트
      • 문제풀이
        • C언어
        • python 파이썬
  • 인기 글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.2
DDD Developer
9. 다양한 입출력 함수들
상단으로

티스토리툴바