Re: [gnet] Reading data from a socket
- From: Tim Müller <tim-mailinglists zen co uk>
- To: lorenb mmgsecurity com, gnet lists gnetlibrary org
- Cc:
- Subject: Re: [gnet] Reading data from a socket
- Date: Wed, 21 Jan 2004 22:09:53 +0000
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]