#include <sys/socket.h>
// 성공 시 전송된 바이트 수, 실패 시 -1 반환
ssize_t send(int sockfd, const void * buf, size_t nbytes, int flags);
// 성공 시 수신한 바이트 수(EOF = 0), 실패 시 -1 반환
ssize_t recv(int sockfd, void * buf, size_t nbytes, int flags);
매개변수로 전달 가능한 옵션의 종류와 의미는 아래와 같음.
"데이터를 모아서 전송하고, 모아서 수신하는 기능의 함수"
적절한 상황에서 사용하면 입출력 함수 호출 수를 줄일 수 있다.
#include <sys/uio.h>
// 성공 시 전송된 바이트 수, 실패 시 -1
ssize_t writev(int filedes, const struct iovec * iov, int iovcnt);
struct iovec
{
void * iov_base; // 버퍼의 주소 정보
size_t iov_len; // 버퍼의 크기 정보
}
#include <sys/uio.h>
// 성공 시 수신된 바이트 수, 실패 시 -1
ssize_t readv(int filedes, const struct iovec * iov, int iovcnt);
send / recv 와 readv/writev 에 대해 배운 챕터였다.
나는 ft_irc를 구현할 때, 단순히 write / read를 활용하여 입출력을 진행했다. 뭔가 굳이 send / recv를 사용해야하나 싶은 생각이 들었던 것 같다. 하지만 이 함수들을 이용한다면, 데이터 전송을 세부적으로 다룰 수 있었을 것 같다. (다만 그게 서브젝트에서 요구하는 사항들을 구현하는데 꼭 필요한지는 잘 모르겠다) send, recv의 MSG_OOB 긴급 메시지 처리를 위해서는 SIGURG 에 대한 시그널 핸들링 함수가 필요하였다. 단순히 메시지를 주고받고에 끝나는 것이 아니라 그 메시지에 함축될 수 있는 의미가 다양하다는 것을 알게되었다.
오히려 readv, writev에 관심이 갔다. 여러 버퍼에 나뉘어 저장되어 있는 데이터를 한번에 전송할 수 있고, readv를 통해 데이터를 여러 버퍼에 나누어 수신할 수 있다는 점 때문이다. 반복적인 함수 호출 없이 깔끔하게 입출력이 가능하다는 점에서 흥미로웠다. 전송해야할 데이터가 여러 개의 배열로 나뉘어 있는 경우, writev를 통해 한번에 보내면 되니까, irc에서 클라이언트로 응답을 해줘야할 때, prefix, cmd, params로 구분되어 있는 메시지를 각각의 배열로 두고있다가, writev를 통해 한번에 보내는 것이 더 효율적이겠다 싶었음.