Saturday, 1 September 2012

PyGtk TCP/IP Server

This page presents a TCP server in PyGTK.

The script is a PyGtk program which accept calls from a terminal client, the TCP/IP Sockets Client Side script, on the same machine.
  1. Run the script below and the server will start to listen call from port 5000.
  2. Run the client script in the same machine, the client will start to connect with the server through port 5000.
  3. In the client, enter any message and send it to the server.
  4. See what happens in the server.
  5. In the client, enter c to close the client connection without closing the server.
  6. For demonstration purpose, the server can only accept 1 client.
  7. Non blocking modes and timer triggers are applied on the server side so that the server window can handle other events while waiting for calls.

Source Code


# Title        : PyGtk TCP/IP Echo Server - Single Client
# Author       : Michael Mui
# Date         : 31/08/2012
# Version      : 0.1
# Remark       : A TCP/IP server that can accept a single
#              : client. Messages from the client will be
#              : printed in the server and echo back to
#              : the client.

import pygtk
pygtk.require('2.0')
import gtk, pango, gobject
import socket

# server port number
gPort = 5000

class Base:
    def __init__(self):
        # define window
        self.Win = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.Win.connect("delete_event", self.WinDelete_event)
        self.Win.set_title("TCP Server")
        # Set the border width of the window
        self.Win.set_border_width(6)
        self.Win.set_size_request(250,350)
        # define a vbox
        self.vbox = gtk.VBox(False, spacing=2)
        self.vbox.show()

        # define a label
        self.lab01 = gtk.Label('Port: '+str(gPort))
        self.lab01.show()
        self.vbox.pack_start(self.lab01,False,False)
        
        # define a list
        self.lstore = gtk.ListStore(gobject.TYPE_STRING)
        self.listView = gtk.TreeView(self.lstore)
        # hide the column header of the list
        self.listView.set_headers_visible(False)
        mCellRend = gtk.CellRendererText()
        # text = 0 means get data from [0] of the list store lstore
        self.tvcol01 = gtk.TreeViewColumn(None,mCellRend, text=0)
        
        # attach treeviewcolumn to list
        self.listView.append_column(self.tvcol01)
        self.listView.show()

        # define scroll window to hold the list
        self.scrollwin = gtk.ScrolledWindow()
        self.scrollwin.set_policy(
            gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.scrollwin.set_shadow_type(gtk.SHADOW_IN)
        self.scrollwin.add(self.listView)
        self.scrollwin.show()
        self.vbox.pack_start(self.scrollwin,True,True)

        # define a button
        self.but01 = gtk.Button("Listen")
        self.but01.set_size_request(0,40)
        self.but01.connect("clicked", self.callback, "switchSer")
        self.but01.show()
        self.vbox.pack_end(self.but01,False)

        self.Win.add(self.vbox)
        self.Win.show()

        # tcp server
        self.server_socket = None
        self.client_socket = None
        self.runServer = False


    # Event Handlers
    # --------------------------------------------------------------
    # Delete event
    def WinDelete_event(self, widget, event, data=None):
        if self.client_socket<>None:
            self.client_socket.close()
        if self.server_socket<>None:
            self.server_socket.close()
        gtk.main_quit()
        return False

    # internal callback
    def callback(self, widget, data):
        if data == 'switchSer':
            if not self.runServer:
                self.runServer = True
                self.but01.set_label("Stop")
                self.appendMsg('Listening for client...')
                self.createSerSocket()
                # start listening to port for every 0.1 sec
                gobject.timeout_add(100, self.LisTrigger)
            else:
                #stop listening to port
                self.runServer = False
                self.but01.set_label("Listen")
                self.appendMsg('Stopped.')
                self.appendMsg('='*20)
                if self.server_socket<>None:
                    self.server_socket.close()
        
    # create server socket
    def createSerSocket(self):
        self.server_socket = socket.socket( \
            socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.bind(("", gPort))
        self.server_socket.setblocking(0) # non-blocking
        
    # listener to server socket (run for every 0.1 sec)
    # looking for new coming client
    def LisTrigger(self):
        #print "looking for client..."
        if self.runServer:
            try:
                self.server_socket.listen(1)
                self.client_socket, maddr = \
                    self.server_socket.accept()
                self.appendMsg('Client from %s' % maddr[0])
                self.client_socket.setblocking(0) # non-blocking
                gobject.timeout_add(100, self.LisCliTrigger)
                return False # stop listening on server socket
            except:
                pass
            return True # keep on listening
        else:
            if self.client_socket <> None:
                self.client_socket.close()
            return False # stop listening

    # listener to client socket (run for every 0.1 sec)
    def LisCliTrigger(self):
        #print "reading client socket..."
        try:
            mdata = self.client_socket.recv(512)
            if mdata=='c':
                # close client
                self.appendMsg('Client is closed.')
                self.client_socket.close()
                gobject.timeout_add(100, self.LisTrigger)
                self.appendMsg('Listening for client...')
                return False
            elif mdata == "":
                self.appendMsg('Client lost connection.')
                gobject.timeout_add(100, self.LisTrigger)
                self.appendMsg('Listening for client...')
                return False
            elif mdata <> False:
                self.appendMsg('Client: '+mdata)
                # echo to client
                mMsg = "%s\n" % mdata
                self.client_socket.send(mMsg)
        except:
            # client socket waiting...
            pass
        return True

    # append message to the list
    def appendMsg(self, pMsg):
        # append to the end of the list
        self.lstore.append((pMsg,))
        # scroll to and select the new message
        mLast = len(self.lstore)
        mLast -= 1
        self.listView.scroll_to_cell(mLast, None)
        self.listView.get_selection().select_path(mLast)

def main():
    gtk.main()

if __name__ == "__main__":
    base = Base()
    main()

Output


Client Side


Server Side

No comments:

Post a Comment