티스토리 뷰

C | C++

데이터 그램 소켓 사용하기

야라바 2018. 6. 17. 17:31
728x90

☞ sendto, recvfrom

<sys/socket.h>

ssize_t sendto(int socket, const void *buffer, size_t size, int flags, struct sockaddr *addr, socklen_t length);
ssize_t recvfrom(int socket, void *buffer, size_t size, int flags, struct sockaddr *addr, socklen_t *lenptr);

데이터 그램 소켓은 비연결 기반의 메시지 전달로 내용과 순서에 신뢰성을 확보 할 수 없습니다. 각 전송 단위마다 수신 주소를 지정합니다. 연결 기반 소켓에 사용하는 listen(), accept(), connect()등은 데이터 그램 소켓에 적용되지 않지만, connect()를 데이터그램(SOCK_DGRAM)에 사용하는 경우는 연결 기반 소켓으로 동작하는 것은 아니고 기본 목적지로 적용됩니다. 기본 목적지가 있는 데이터 그램 소켓에는 write(), send()를 사용할 수 있습니다.

sendto()는 *addr과 *lenptr 지정한 호스트에 메시지를 전송합니다. flags는 send()와 같은 방식으로 적용합니다. 성공하면 전송된 바이트수를 리턴하고 실패하면 -1을 리턴하지만 메시지가 실제로 지정한 호스트에 전달되었는지는 확인할 수 없습니다.

recvfrom()에서 인수 *addr를 NULL로 넘기거나 recv()를 사용하면 어디에서 보낸 메시지인지 무시하고 메시지만을 읽습니다. *addr과 *lenptr를 전달하면 메시지를 전송한 호스트의 정보를 함께 저장합니다. size는 최대 메시지의 길이로 전달된 메시지가 이 값 보다 길면 size까지만 읽히고 나머지는 버려집니다. 최대 메시지 길이를 감안하여 데이터 그램 읽기를 수행해야 합니다.



☞ 예제1

static void hb_cluster_send_heartbeat_internal (struct sockaddr_in *saddr, socklen_t saddr_len, char *dest_host_name, bool is_req)
{
	HBP_HEADER *hbp_header;
	char buffer[HB_BUFFER_SZ], *p;
	size_t hb_len;
	int send_len;

	memset ((void *) buffer, 0, sizeof (buffer));
	hbp_header = (HBP_HEADER *) (&buffer[0]);

	hb_set_net_header (hbp_header, HBP_CLUSTER_HEARTBEAT, is_req, OR_INT_SIZE, 0, dest_host_name);

	p = (char *) (hbp_header + 1);
	p = or_pack_int (p, hb_Cluster->state);

	hb_len = sizeof (HBP_HEADER) + OR_INT_SIZE;

	send_len = sendto (hb_Cluster->sfd, (void *) &buffer[0], hb_len, 0, (struct sockaddr *) saddr, saddr_len);
	if (send_len <= 0)
	{
		MASTER_ER_LOG_DEBUG (ARG_FILE_LINE, "sendto failed. \n");
	}

	return;
}

static void *hb_thread_cluster_reader (void *arg)
{
	int error;
	SOCKET sfd;
	char buffer[HB_BUFFER_SZ + MAX_ALIGNMENT], *aligned_buffer;
	int len;
	struct pollfd po[1] = { {0, 0, 0} };

	struct sockaddr_in from;
	socklen_t from_len;

	aligned_buffer = PTR_ALIGN (buffer, MAX_ALIGNMENT);
	sfd = hb_Cluster->sfd;
	while (hb_Cluster->shutdown == false)
	{
		po[0].fd = sfd;
		po[0].events = POLLIN;
		error = poll (po, 1, 1);
		if (error <= 0)
		{
			continue;
		}

		if ((po[0].revents & POLLIN) && sfd == hb_Cluster->sfd)
		{
			from_len = sizeof (from);
			len = recvfrom (sfd, (void *) aligned_buffer, HB_BUFFER_SZ, 0, (struct sockaddr *) &from, &from_len);
			if (len > 0)
			{
				hb_cluster_receive_heartbeat (aligned_buffer, len, &from, from_len);
			}
		}
	}

	return NULL;
}


위의 예제 코드는 큐브리드 DBMS에서 클러스터링 기능을 구현하는데 적용한 데이터그램 사용 예제입니다.




728x90

'C | C++' 카테고리의 다른 글

시스템 로그  (0) 2018.06.29
터미널 IO  (0) 2018.06.29
연결 기반으로 소켓 사용하기  (0) 2018.06.17
소켓 생성 및 닫기  (0) 2018.06.17
소켓 바이트 오더 변환  (0) 2018.06.17