Re: GIOChannel issues



On Sunday 11 December 2005 01:43, Travis Miller wrote:
> Hello,
>
> I am trying to use GIOChannel in order to use sockets in a simple way (I
> am trying to get notification on events like read and disconnect).
> Anyway, here is the code that creates the GIOCHannel
>
> void
> on_ListenButton_clicked                (GtkButton       *button,
>                                         gpointer         user_data)
> {
> 	GtkWidget *text = lookup_widget(GTK_WIDGET(button),
> "StatusText");
>
> 	// create the listening socket
> 	int sockfd, new_fd;
>     	struct sockaddr_in my_addr;
>     	struct sockaddr_in their_addr;
>     	int sin_size;
>
>    	 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
>       	  perror("socket");
>       	  exit(1);
>     	}
>
> 	my_addr.sin_family = AF_INET;
>    	my_addr.sin_port = htons(1352);
>    	my_addr.sin_addr.s_addr = INADDR_ANY;
>     	bzero(&(my_addr.sin_zero), 8);
>
>     	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct
> 			sockaddr)) == -1) {
> 	        perror("bind");
> 	        exit(1);
> 	}
>
>
> 	if (listen(sockfd, 5) == -1) {
>         	perror("listen");
>        	 	exit(1);
>     	}
> 	gtk_entry_set_text(GTK_ENTRY(text), "Listening");
>
> 	sin_size = sizeof(struct sockaddr_in);
>     	if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
> 			&sin_size)) == -1) {
> 	        perror("accept");
>     	}
>
> 	// we got a socket so set text box
> 	gtk_entry_set_text(GTK_ENTRY(text), "Connection accepted");
>
> 	// now create GIOChannel from connection
> 	GIOChannel *iochannel = g_io_channel_unix_new(new_fd);
>
> 	// now add to main event loop
> 	GtkWidget *window = lookup_widget(GTK_WIDGET(button),
> 						"MainWindow");
> 	g_io_add_watch(iochannel, G_IO_IN, (GIOFunc *) &ReceiveData,
> 						(gpointer) window);
>
>
> 	// now close the listener
> 	close(sockfd);
>
> }
>
> The function g_io_watch() ties to the G_IO_IN (there is data to read on
> the socket) event to the function ReceiveData that is defined as
>
> gboolean ReceiveData(GIOChannel *source, GIOCondition condition,
> gpointer data)
> {
> 	gchar buf[500];
> 	int bytes_read;
> 	GtkWidget *text = NULL;
> 	GQuark quark;
> 	GError *error = NULL;
> 	gint sd;
>
>
>
> 	g_print("data received\n");
> 	text = lookup_widget(GTK_WIDGET(data), "StatusText");
> 	gtk_entry_set_text(GTK_ENTRY(text), "received data");
>
> 	sd = g_io_channel_unix_get_fd(source);
>
> 	bytes_read = recv(sd, buf, 500, 0);
>
> 	if(bytes_read == -1) {
> 		g_print("error\n");
> 	}
> 	else {
> 		buf[bytes_read] = '\0';
> 		g_print("buf = %s\n", buf);
> 		text = lookup_widget(GTK_WIDGET(data), "ReceivedText");
> 		gtk_entry_set_text(GTK_ENTRY(text), buf);
> 	}
>
> 	return TRUE;
> }
>
> The problem is this.  If the client closes the connection then I get a
> flood of empty buffers and the ReceiveData() function is repeatedly
> called.  What could cause this weird behavior?

I cannot see where you disconnect the callback.  The easiest way to do that is 
to call g_io_channel_unref() on the iochannel pointer immediately after you 
have called g_io_add_watch() on it.  g_io_channel_unix_new() returns a 
GIOChannel object with a reference count of one.  g_io_add_watch() adds a 
further reference count - if you decrement it by 1, the callback will be 
disconnected and the relevant GSource object removed as soon either the 
callback returns FALSE or you call g_source_remove() on the return value of 
g_io_add_watch() - so detect the closing of the socket by the peer in the 
callback (read()/recv() returning 0 and/or the G_IO_HUP condition arising in 
your 'condition' variable) and return FALSE upon that occurring, or store the 
return value of g_io_add_watch() and call g_source_remove() on it.

For the result you mention to occur, it appears therefore that specifying the 
G_IO_IN condition flag in g_io_add_watch() will cause the callback to be 
called even if the the socket is in error condition or the socket is closed, 
without actually specifying the G_IO_HUP or G_IO_ERR flags.

Chris




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