ring buffer 의 사용이유

avatar80의 이미지

고정된 메모리에서 버퍼를 잡고 썼다 지웠다 하는데요.

링버퍼를 사용해야 된다고 하는군요..

그런데 정확하게 링버퍼를 왜 사용하는지 잘 모르겟습니다..

고수들의 조언 부탁드려요..

choissi의 이미지

링버퍼의 장점은 순환할수 있다지요.

링버퍼의 구현은 선형의 버퍼이지만
논리적으로 시작과 끝이 만나 있어서 계속
순환하면서 버퍼를 쓸수 있습니다.

네트워크 송수신 버퍼로 사용하기에 좋습니다.

울랄라~ 호기심 천국~!!
http://www.ezdoum.com

choissi의 이미지

아래는 링버퍼를 사용한 예입니다.
ClientDataHandler 가 집어 넣는 넘이고
MakePacket가 꺼내 쓰는 넘이지요..

typedef struct _FD_QUEUE{		/* FD QUEUE(원형)   */
    unsigned char	Queue[BUFF_LEN];/* fd data buffer   */
    int			fd;		/* fd 번호          */
    int			sttime;		/* conn time        */
    int			Pos;		/* 큐의 끝          */
    int			PkCurr;		/* 큐의 시작        */
    int			cnt;		/* fd패킷 만든 횟수 */
}FD_QUEUE;


/*******************************************************************************
 * 설명	  : 큐에 있는 것으로 패킷을 만든다.
 * Prototype : MakePacket(fd)
 * Arguments :
 * Return	:
 ******************************************************************************/
int MakePacket(fd)
int fd;
{
register unsigned char *src;
char    packet[PACKET_LEN];
char	ptmp[5];
FD_PACKET   *fdp;
int	plen = 0, plen2 = 0;
int	rtn = 0, dif = 0;
	
	memset(packet, 0x00, sizeof(packet));
	memset(ptmp, 0x00, sizeof(ptmp));
			
	while(1){
		
		src = (unsigned char *)(fdq[fd]->Queue + fdq[fd]->PkCurr);
		
		/* 패킷 만들어야 할 사이즈는 얼마? */	
		if((fdq[fd]->PkCurr + PACKET_SIZE) >= BUFF_LEN){ 
			dif = BUFF_LEN - fdq[fd]->PkCurr;
			memcpy(ptmp, src, dif);
			memcpy(ptmp + dif, fdq[fd]->Queue, PACKET_SIZE - dif);
		}else{
			memcpy(ptmp, src, PACKET_SIZE);
		}
		plen = atoi(ptmp) + 4;
        	
		/* 패킷이 크면,, 한방에 안만들어 진다. 버퍼에 원하는 사이즈
		   만큼 들어 왔는지 확인해보자.. */		   				  
		plen2 = (fdq[fd]->Pos < fdq[fd]->PkCurr) ? BUFF_LEN + fdq[fd]->Pos : fdq[fd]->Pos;
		plen2 = plen2 - fdq[fd]->PkCurr;
		if(plen2  < plen) {
			OUT("[%s] : [Msg] fd[%02d] MakePacket SAVE ptmp[%4s] plen[%d] plen2[%d]\n", 
				pname, fd, ptmp ,plen, plen2);
			return 1;
		}
        	
		/* 패킷을 맹글어 볼까나 */
		OUT("[%s] : [Msg] fd[%02d] MakePacket START ptmp[%4s] plen[%d] plen2[%d]\n", 
			pname, fd, ptmp ,plen, plen2);
		        	
		if((fdq[fd]->PkCurr + plen) >= BUFF_LEN){
			dif = BUFF_LEN - fdq[fd]->PkCurr;
			memcpy(packet, src, dif);
			memcpy(packet + dif, fdq[fd]->Queue, plen - dif);
			fdq[fd]->PkCurr	= plen - dif;
		}else{
			memcpy(packet, src, plen);
			fdq[fd]->PkCurr	+= plen;
		}					
		OUT("[%s] : [Msg] fd[%02d] MakePacket >> END!! plen[%d] dif[%d]\n", pname, fd, plen, dif);
					
		/* 만들어진 패킷을 safe 쓰레드 변수로 옮긴다. 
		 * malloc은 WorkerThread에서 free
		 */
        	
		fdp = calloc(1, sizeof(FD_PACKET));		
		memcpy(fdp->Packet, packet, plen);
		fdp->fd = fd;
		fdp->len = plen;
		fdp->sttime =  fdq[fd]->sttime;
											
		/* tpool job큐에 등록 */
		rtn = tpool_add_work(zt_pool, WorkerThread, fdp);
		OUT("[%s] : [Msg] fd[%02d] MakePacket Thread pool add rtn[%d]\n", pname, fd, rtn);

		if(fdq[fd]->PkCurr >= fdq[fd]->Pos) break; /* 큐에 들어온거 다 살펴 봤당.. 그만 루프 빠지자 */ 
	}	
	return 1;
}


/*****************************************************************************
 * 설명	  : Client 의 Data를 처리하는 Handler
 * Prototype : int ClientDataHandler(event, fd, type)
 * Arguments :
 * Return	:
 ****************************************************************************/
int ClientDataHandler(event, fd ,type)
EVENT *event;
int	fd, type;
{
int  rtn;
int  dif = 0;
int  errcnt = 0;
char buff[4096];

start:

	memset(buff, 0x00, sizeof(buff));
	rtn = read(fd, buff, sizeof(buff));

	/****
	OUT("[%s] : [Msg] ClientDataHandler READ fd[%02d] buff[%s] rtn[%d]\n", pname, fd, buff, rtn);
	****/
	fdq[fd]->cnt++;
	
	if(rtn <= 0){ /* 컨넥션 끝났거나, 에러 받았다... */
	
		if(errno == EINTR && errcnt < 3) { /* 인터럽트(시그널)에 의한 에러는 봐준다.. 
			   				* (어쩌다 함씩 생긴당.. 주의) 
							*/
			errcnt ++;
			OUT("[%s] : [Err] fd[%02d] ClientDataHandler TRcnt[%d] errno[EINTR] errcnt[%d]\n", 
				pname, fd, fdq[fd]->cnt, errcnt);
			usleep(1000);
			goto start;
		
		}else{ /* 컨넥션 정리 작업을 한다. 
			* 1) 동적할당 소켓큐 해제, 
			* 2) 소켓 close */

			OUT("[%s] : [Err] fd[%02d] ClientDataHandler Connect Close TRcnt[%d] errno[%d][%s]\n", 
				pname, fd, fdq[fd]->cnt, errno, strerror(errno));
						
			free(fdq[fd]);
			fdq[fd] = NULL;
		
			close(fd);
			AppDelEvent(event, type);
		}
		return 1;
	
	}
	/*
	OUT("[%s] : [Msg] ClientDataHandler READ fd[%02d] buff[%s] rtn[%d]\n", pname, fd, buff, rtn);
	OUT("[%s] : [Msg] ClientDataHandler READ fd[%02d] rtn[%d] Cur[%d] Pos[%d] cnt[%d]\n", 
		pname, fd, rtn, fdq[fd]->PkCurr, fdq[fd]->Pos, fdq[fd]->cnt);
	*/
	if((fdq[fd]->Pos + rtn) >= BUFF_LEN){		
		dif = BUFF_LEN -  fdq[fd]->Pos;
		memcpy(fdq[fd]->Queue + fdq[fd]->Pos, buff, dif);
		memcpy(fdq[fd]->Queue, buff + dif, rtn - dif);
		fdq[fd]->Pos = rtn - dif;
	}else{
		memcpy(fdq[fd]->Queue + fdq[fd]->Pos , buff, rtn);
		fdq[fd]->Pos += rtn;
	}
	OUT("[%s] : [Msg] fd[%02d] ClientDataHandler READ rtn[%d] Cur[%d] Pos[%d] cnt[%d]\n", 
		pname, fd, rtn, fdq[fd]->PkCurr, fdq[fd]->Pos, fdq[fd]->cnt);
	
	MakePacket(fd);
	return 1;
}

울랄라~ 호기심 천국~!!
http://www.ezdoum.com

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.