Re: Using GSocket in a GTK application



On Wednesday 23 February 2011 08:01:12 you wrote:
On Tue, 22 Feb 2011 23:25:43 -0500
Jacques Pelletier <jpelletier ieee org> wrote:
[snip]

...

      /* Connect asynchronously */
      
      mySocketClient = g_socket_client_new();
      
      g_socket_client_connect_to_host_async(
      
        mySocketClient,
        myUrl,
        myPort,
        NULL,
        my_client_connect_async_function,
        NULL);

...


void my_client_connect_async_function(GObject *source_object,

                          GAsyncResult *res,
                          gpointer user_data)

{

  mySocketConnection =

g_socket_client_connect_to_host_finish(source_object,res,NULL);

  if (mySocketConnection != NULL)
  
    {
    
      mySocket = g_socket_connection_get_socket(mySocketConnection);
      mySource = g_socket_create_source(mySocket,
      
                                                                    G_IO_IN
| 
| G_IO_PRI | G_IO_NVAL, NULL);
| 
      g_source_set_callback(mySource, myCallback,NULL,NULL);
      mySource_id = g_source_attach(mySource,NULL);
    
    /* Instructions for updating the GUI */
    
    }
  
  else
  {
    
    /* Socket connection failed */
    
  }

}

/* Process incoming data from socket */
gboolean myCallback(GSocket *source, GIOCondition condition, gpointer
data) {

  int Input_Length;
  gchar Receive_Buffer[1024];
  
  switch (condition)
    
    {
    
      /* Check for socket error */
    
    case (G_IO_ERR | G_IO_HUP):
    
    case G_IO_HUP:
      g_message("Socket error HUP\n");
      
      PortClose();
      
      goto error;
    
    case (G_IO_ERR | G_IO_NVAL):
    
    case (G_IO_NVAL):
      g_message("Socket error NVAL\n");
      goto error;
      
      /* Check for data to be read (or if the socket was closed)

*/ case G_IO_IN:
      Input_Length = g_socket_receive(source, (gchar

*)Receive_Buffer,1024,NULL,NULL);

      if (Input_Length != -1)
            
            {
            
                    /* Update GUI according to the received data

*/ MyGuiUpdate(Receive_Buffer,Input_Length);

            }
            
      break;
    
    default:
      ;
    
    } /* condition */
    
  /* Returns TRUE so it remains installed until we remove it */
  return TRUE;
 
 error:
  return FALSE;

}

void SocketClose(void)
{

  g_socket_close(mySocket,NULL);
  g_object_unref(mySocketConnection);
  g_object_unref(mySocketClient);
  g_source_unref(mySource);

}


Any comments about how to improve, missing code, etc.?

Your callback seems to rely on the ability reliably to detect an
end-of-file on the socket by means of the G_IO_HUP revent poll
condition. However, you can't rely on that: see
http://www.greenend.org.uk/rjk/2001/06/poll.html .

From looking at the implemention of g_socket_receive_with_blocking() in
gio's socket.c, g_socket_receive() returns 0 (like recv()/read())
rather than returning -1 and an error, on encountering end-of-file (to
that extent the statement in the documentation that "if the socket is
in blocking mode the call will block until there is some data to
receive or there is an error" appears to be wrong, since it will also
unblock on orderly close down of the remote peer). However, your code
doesn't act on either outcome from g_socket_receive().

I also didn't understand your switch fall-throughs - I avoid bit
testing in switch statements - but they appear to treat G_IO_ERR and
G_IO_HUP as the same, and view G_IO_HUP as an error, which it isn't
except in the limited sense that you don't expect the server to close
its end first. A G_IO_HUP event will become G_IO_ERR on further read
attempts of course, and maybe that was your design approach on that
point, except that your switch statements don't accommodate a case where
the G_IO_ERR flag is set and none of the others are.

On a minor point, in this kind of usage I always call g_source_unref()
immediately after g_source_attach() (g_source_attach() will increment
the reference count).  

I wasn't sure when exactly was the best moment to call g_source_unref().
I'm not very familiar with this concept and I don't know if there could be 
some problems with memory allocations and releases.

This saves having to call it in SocketClose()
(instead the source object will be destroyed as soon as the callback
returns FALSE).  As it happens, SocketCLose() isn't called in your code
snippet but no doubt something else does that.

As someone else has mentioned however, GSocketConnection inherits from
GIOStream, and if you use the GIOStream interface you can do an
asynchronous read with g_input_stream_read_async() via
g_io_stream_get_input_stream(), which does all this stuff for you.

If it makes the code simpler and easier to read, I'll go with that.

Many thanks for your contribution, I'll check all that carefully.

JP


Chris



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