[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] socket message boundary problem



On Mon, May 31, 2010 at 1:14 PM, Hor Meng Yoong <yoonghm@xxxxxxxxx> wrote:
> Hi:
>
>   I am using libevent2. Is that a wrapper function/library to send and
> receive fixed length message, or variable length message with message length
> embedded in the first 2 bytes with libevent2? Thank

Got all three of your messages.  No need to send so many!

There's no built-in function to do this, but it's very easy to do with
bufferevents.  Here's some example demo code to show you the general
idea of how it's done:


#include <event2/bufferevent.h>
#include <event2/buffer.h>

#define MSG_LEN 512

int
send_fixed_msg(struct bufferevent *bev, const char *msg)
{
	bufferevent_write(bev, msg, MSG_LEN);
	return 0;
}

void
fixed_msg_readcb(struct bufferevent *bev, void *ctx)
{
	char msg_buf[MSG_LEN];
	struct evbuffer *inp = bufferevent_get_input(bev);
	while (evbuffer_get_length(inp) >= MSG_LEN) {
		evbuffer_remove(inp, msg_buf, MSG_LEN);
		/* Here's where you add code to handle the contents of
		 * msg_buf */
	}
}

void
setup_fixed_msg_bufferevent(struct bufferevent *bev)
{
	/* Set up the read callback to be invoked when we have some bytes that
	   have arrived. In practice, you'd also want to set the other
	   callbacks, and maybe provide some data too. */
	bufferevent_setcb(bev, fixed_msg_readcb, NULL, NULL, NULL);
}


/* Now, variable-length messages.  Let's assume that the message format
 * is a two-byte length value encoded in big-endian (network) order,
 * plus that number of bytes worth of message */
int
send_var_msg(struct bufferevent *bev, const char *msg, int length)
{
	ev_uint16_t len_encoded;
	if (length < 0 || length > 65535)
		return -1;
	len_encoded = htons(length);
	bufferevent_write(bev, &len_encoded, 2);
	bufferevent_write(bev, msg, length);
	return 0;
}

void
var_msg_readcb(struct bufferevent *bev, void *ctx)
{
	struct evbuffer *inp = bufferevent_get_input(bev);
	char msg_buf[65536];
	ev_uint16_t len_encoded;
	int msglen;
	while (1) {
		int len_in_buf = evbuffer_get_length(inp);
		if (len_in_buf < 2)
			return;
		/* We have enough data to read a length field.  For now,
		 * just inspect it but don't remove it.
		 */
		evbuffer_copyout(inp, &len_encoded, 2);
		msglen = ntohs(len_encoded);
	        if (len_in_buf < 2 + msglen) {
			/* The entire message hasn't arrived yet. */
			return;
		}
		/* The message is here; pull it out of the buffer. */
		evbuffer_drain(inp, 2); /*discard the length field */
		evbuffer_remove(inp, msg_buf, msglen);

		/* Here's where you add code to handle the contents of
		 * msg_buf */
	}
}

void
setup_var_msg_bufferevent(struct bufferevent *bev)
{
	/* Set up the read callback to be invoked when we have some bytes that
	   have arrived. In practice, you'd also want to set the other
	   callbacks, and maybe provide some data too. */
	bufferevent_setcb(bev, var_msg_readcb, NULL, NULL, NULL);
}



Note that in practice you might want to use watermarks to avoid
extraneous calls to the _readcb functions.  For more info on the
bufferevent API, check out chapter Ref6 of
http://www.wangafu.net/~nickm/libevent-book/ .

hope this helps,
-- 
Nick
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.