Idioma:
English
En esta página
GUI
Código cliente
Código servidor
Gracias
Temas
GIOChannel
Gio.IOChannel
FIFO chat
Socket chat
El ejemplo que signe muestra como conectar algunos eventos con rutinas utilizando IOChannels. En ejemplo utilizamos el reloj de tiempo real (RTC) disponible en cada PC para generar llamadas cadad segundo, y nos conectamos con internet con zocalos con la internet.
El programa brinde lo siguiente:
NOTAS:
#!/usr/bin/env python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 8 -*-
#
# main.py
# Copyright (C) 2019 John Coppens <john@jcoppens.com>
#
# test_multi is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# test_multi is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, Gio
import os, sys
import pdb
import socket
import fcntl
import subprocess as sp
UI_FILE = "test_multi.ui"
RTC_DEV = "/dev/rtc0"
IP = "127.0.0.1"
PORT = 9999
XTERM = "xterm"
RTC_UIE_ON = 0x00007003
class RTC():
""" RTC connects a handler to the RTC device (normally /dev/rtc0)
<callback> parameter if defined, will be called on each tick
<viewer> parameter if defined, must be a Gtk.TextView, and a
character will be inserted on each tick
NOTE: At the moment, the 'tick' signal is the default 1 second period.
The rate can be changed with ioctl commands, but this is NOT
implemented here for simplicity.
"""
def __init__(self, parent, viewer = None, callback = None):
self.parent = parent
self.callback = callback
self.viewer = viewer
self.rtc = open(RTC_DEV, "rb")
if not self.rtc:
print("Can't open file:", RTC_DEV)
exit(1)
self.ioch = GLib.IOChannel.unix_new(self.rtc.fileno())
# Datos leidos del RTC son del tipo 'long': No son caracteres validos
# y es preciso de deshabilitar la codificacion:
self.ioch.set_encoding(None)
GLib.io_add_watch(self.ioch, GLib.IO_IN, self.read)
self.enable_interrupts()
def read(self, ioch, par2):
try:
data = self.ioch.read(8) # Cada 'long' tiene 8 bytes
self.append_text("@")
except Exception as e:
print(e)
print("Data read contains strange things")
return True
def enable_interrupts(self):
r = fcntl.ioctl(self.rtc, RTC_UIE_ON, 0)
if r == -1:
print("Could not enable interrupts")
def append_text(self, txt):
if self.callback != None:
self.callback(txt)
bff = self.viewer.get_buffer()
bff.insert(bff.get_end_iter(), txt)
def disable_interrupts(self):
fcntl.ioctl(self.rtc, RTC_UIE_OFF, 0);
class TCP_client():
""" The TCP client tries to connect to the server on instantiation of the
class. So the server must be running!
<callback> parameter if defined, will be called with the data
received on the TCP port.
<viewer> parameter if defined, must be a Gtk.TextView, and
will be updated with the received data.
semd method can be called to send a message to the
TCP port
"""
def __init__(self, host, port,
callback = None,
viewer = None):
self.callback = callback
self.viewer = viewer
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((host, port))
self.socket.setblocking(False)
self.fd = self.socket.fileno() # Obtener el file descriptor
print("Connected to {}".format(host))
GLib.io_add_watch(self.fd, GLib.IO_IN, self.process_input)
# Instalar la funcion en caso
# de datos recibidos
def process_input(self, skt, cond):
""" This function is called asynchronously when data is received.
"""
msg = self.socket.recv(100) # Recibir el mensage de la red
if self.callback != None:
self.callback(msg)
bff = self.viewer.get_buffer()
bff.insert(bff.get_end_iter(), msg.decode("latin-1"))
return True # Queremos quedar activos
def send(self, msg):
self.socket.send(msg.encode("latin-1"))
class GUI:
def __init__(self):
self.builder = Gtk.Builder()
self.builder.add_from_file(UI_FILE)
self.builder.connect_signals(self)
main_window = self.builder.get_object("MainWindow")
# Make an dictionary of references to widgets we are interested in
# from the UI file
self.obj = {}
for objref in ["from_RTC_buffer",
"from_RTC_view",
"from_socket_buffer",
"from_socket_view"]:
self.obj[objref] = self.builder.get_object(objref)
self.rtc = RTC(self,
viewer = self.obj["from_RTC_view"],
callback = self.process_rtc)
self.tcp = TCP_client(IP, PORT,
viewer = self.obj["from_socket_view"],
callback = self.process_tcp)
self.tcp.send("Simulated server (netcat) \n")
main_window.show_all()
def on_window_destroy(self, window):
Gtk.main_quit()
def process_rtc(self, data):
""" Execute anything which has to be synced with the RTC
"""
print(data)
return True
def process_tcp(self, data):
""" Process the data coming from the server
"""
print(data)
return True
def kbd_entry_activate_cb(self, entry):
""" Send the data from the keyboard to the server (and print
on the terminal
"""
text = entry.get_text()
print(text)
self.tcp.send(text + "\n")
entry.set_text('')
def main():
sp.Popen([XTERM, '-e', 'nc', '-l', '-p', '9999'])
gui = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.20.0 --> <interface> <requires lib="gtk+" version="3.0"/> <object class="GtkTextBuffer" id="from_RTC_buffer"/> <object class="GtkTextBuffer" id="from_kbd_buffer"/> <object class="GtkTextBuffer" id="from_socket_buffer"/> <object class="GtkWindow" id="MainWindow"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="title" translatable="yes">window</property> <property name="default_width">500</property> <property name="default_height">400</property> <signal name="destroy" handler="on_window_destroy" swapped="no"/> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="margin_left">4</property> <property name="margin_right">4</property> <property name="margin_top">4</property> <property name="margin_bottom">4</property> <property name="orientation">vertical</property> <child> <object class="GtkFrame" id="from_RTC"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="margin_top">2</property> <property name="margin_bottom">2</property> <property name="label_xalign">0.05000000074505806</property> <property name="shadow_type">none</property> <child> <object class="GtkAlignment"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="left_padding">12</property> <child> <object class="GtkScrolledWindow"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="shadow_type">in</property> <child> <object class="GtkTextView" id="from_RTC_view"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="wrap_mode">char</property> <property name="buffer">from_RTC_buffer</property> </object> </child> </object> </child> </object> </child> <child type="label"> <object class="GtkLabel"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">From RTC</property> </object> </child> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkFrame" id="from_kbd_frame"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="margin_top">2</property> <property name="margin_bottom">2</property> <property name="vexpand">False</property> <property name="label_xalign">0.05000000074505806</property> <child> <object class="GtkAlignment"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="left_padding">12</property> <child> <object class="GtkEntry" id="kbd_entry"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="has_focus">True</property> <signal name="activate" handler="kbd_entry_activate_cb" swapped="no"/> </object> </child> </object> </child> <child type="label"> <object class="GtkLabel"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">From keyboard</property> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkFrame" id="from_socket_frame"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="margin_top">2</property> <property name="margin_bottom">2</property> <property name="label_xalign">0.05000000074505806</property> <child> <object class="GtkAlignment"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="left_padding">12</property> <child> <object class="GtkTextView" id="from_socket_view"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="wrap_mode">char</property> <property name="buffer">from_socket_buffer</property> </object> </child> </object> </child> <child type="label"> <object class="GtkLabel"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">From socket</property> </object> </child> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> <property name="position">2</property> </packing> </child> </object> </child> </object> </interface>
2249
(c) John Coppens ON6JC/LW3HAZ | correo |