Re: [gnet] Reading data from a socket



On Wednesday 21 January 2004 20:23, Loren Bandiera wrote:

> I'm trying to write some code with GNet that will connect to some ports
> on a machine and read any data (ie. software banners) that might be
> available.
>
> The problem I'm currently having is that I make a call to
> gnet_io_channel_readline there are times it never returns.  If there is
> no data to read it doesn't just fail it seems to get stuck in an
> infinite loop and I have to kill -9 the process.
>
> I've tried using g_timeout_add to timeout the socket but that didn't
> help either.
>
> Here is a stripped down version of my code.  Am I doing something wrong
> or is this a bug?

Apart from the hopefully obvious stuff [1], your problem seems to be that you 
are not using the GLib main loop. All the GIOChannel stuff depends on the 
main loop being run. You have two choices basically: 

(a) write your program events-based, ie. set up everything at the beginning, 
then call g_main_loop_run(), and then handle everything as stuff happens, and 
call g_main_quit() when you want to exit.

(b) do something like this:

          while (want_to_run)
          {
             while (g_main_context_pending(NULL))
                g_main_context_iteration(NULL, FALSE);

             /* do your own stuff here if you want */
             g_usleep(500);
          }

GIOChannels basically work like this:

 * you set up an iochannel from a file descriptor (pipe, socket, whatever)
 * you tell GLib to 'watch' that iochannel for certain events 
    (stuff to read, stuff to write, error, etc.)
 * GLib will then call your callback function when one of the events you
    are watching for has happened on the channel/socket.
 * You then read from the socket if there is stuff to read, or write if there
      is stuff to write, etc.

Attached a (hackish) variation of your program, so you see what I mean.

You might want to use GConn instead of GTcpSocket anyway, btw. I find the 
interface much nicer and much less hassle.

Cheers
-Tim

[1] 
 * you do not check whether gnet_tcp_socket_connect() returned NULL
 * sizeof(buf) will return sizeof(gchar *) = 4, and not the size that you
    allocated dynamically with g_malloc()!

#include <glib.h>
#include <gnet.h>
#include <string.h>

struct helper
{
  GTcpSocket *socket;
	gsize       bufsize;
	gchar      *buf;
};

static gboolean
io_callback (GIOChannel *c, GIOCondition cond, gpointer data)
{
	struct helper *h = (struct helper *)data;

	g_print("%s:%u - ",
    gnet_inetaddr_get_canonical_name(gnet_tcp_socket_get_remote_inetaddr(h->socket)),
    gnet_tcp_socket_get_port(h->socket));

	if ((cond & G_IO_IN))
	{
		gchar  buf[256];
		gsize  bytes_read;

		g_print ("G_IO_IN\n");
		g_print ("\tbefore read\n");
		gnet_io_channel_readline (c, buf, sizeof(buf), &bytes_read);
		g_print ("\tafter read (got %u bytes)\n", bytes_read);

		if (bytes_read == 0)
		{
		  g_print("\tsocket closed by remote end.\n");
			return FALSE;
		}

		h->buf = g_realloc(h->buf, h->bufsize + bytes_read);
		memcpy(h->buf + h->bufsize, buf, bytes_read);
		h->bufsize += bytes_read - 1; /* -1 because bytes_read includes zero-terminator */

		g_print ("\tGot so far: %s\n", h->buf);
	}

	if ((cond & G_IO_NVAL))
	{
		g_print ("G_IO_NVAL\n");
		return FALSE;
	}

	if ((cond & G_IO_ERR))
	{
		g_print ("G_IO_ERR\n");
		return FALSE;
	}

	return TRUE;
}

gint
main (gint argc, gchar *argv[])
{
	GMainLoop *loop;
	gint       ports[4], i;

	ports[0] = 22;
	ports[1] = 111;
	ports[2] = 825;
	ports[3] = 1241;

	for (i = 0; i < 4; i++)
	{
		GTcpSocket *socket = gnet_tcp_socket_connect ("localhost", ports[i]);

		if (!socket)
		{
			g_print("Could not connect to port %d\n", ports[i]);
		}
		else
		{
			struct helper *h;
			GIOChannel    *gio;

 			h = g_new0(struct helper, 1);

			h->socket  = socket;
			h->buf     = NULL;
      h->bufsize = 0;

			gio = gnet_tcp_socket_get_io_channel (socket);
			g_io_add_watch(gio, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, io_callback, h);
		}
	}

	loop = g_main_loop_new(NULL, FALSE);

	g_main_loop_run(loop);

	return 0;
}



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