Is py3270 threadsafe?

652 views
Skip to first unread message

Michael Potter

unread,
May 12, 2014, 2:40:39 PM5/12/14
to blaz...@googlegroups.com
I would like to drive multiple 3270 terminals from one python script using threads.

Is py3270 threadsafe such that I can expect to use the threading library?

What should I know other than what is on the threading documentation:

The purpose of using threads is to load test a 3270 based application by pretending to be multiple users.


Randy Syring

unread,
May 12, 2014, 3:30:08 PM5/12/14
to blaz...@googlegroups.com
Michael,

You can take a look at the code, it's really pretty simple stuff that shells out to a x3270 executable.  I believe, as long as you did one Emulator object per thread, you would be alright.  I think threaded issues come into play when you have shared global state between the threads and I'm not aware of any global state that would be shared as long as you used one Emulator per thread.  If you tried to share an Emulator instance between threads, I'm certain you would have problems there.

I use py3270 in a multi-process configuration using the multiprocess stdlib and have no problems.

Keep in mind that py3270 creates a process for each new connection due to using the x3270 executables.  Therefore, your threading approach will still result in lots of new processes being created.  Not sure if that will matter for your application, but something to keep in mind.

Randy Syring
Husband | Father | Redeemed Sinner

"For what does it profit a man to gain the whole world
and forfeit his soul?" (Mark 8:36 ESV)


--
You received this message because you are subscribed to the Google Groups "BlazeLibs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blazelibs+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Michael Potter

unread,
May 14, 2014, 12:13:04 PM5/14/14
to blaz...@googlegroups.com
I am testing and so far so good.  I am creating an Emulator per thread as Randy suggested.

Kyle Benzo

unread,
May 19, 2014, 5:57:08 PM5/19/14
to blaz...@googlegroups.com
Do either of you have any sample code that I could reference for driving multiple terminals at once?

Thank you,
Kyle

Michael Potter

unread,
May 19, 2014, 6:06:51 PM5/19/14
to blaz...@googlegroups.com
Beware: Not production quality and I did edit a bit with out running.

#!/usr/bin/python

from py3270 import Emulator
from subprocess import call
import threading
import time
import sys
import logging

def runOne(name):
    em = Emulator(visible=True)

    try:
        em.connect('NNN.16.81.137:3270')
    except:
        print "Connection issue - Region probably not started."
        sys.exit(1)

    transId = 'MENU'

    em.fill_field(8, 13, 'USERID', 8)
    em.fill_field(9, 13, 'XXXXXX', 8)
    em.send_enter()
    # if your host unlocks the keyboard before truly being ready you can use:
    # em.wait_for_field()

    em.send_string(transId)
    em.send_enter()
    time.sleep(1)

    em.send_string('123456')
    em.send_enter()

    time.sleep(10)

    em.terminate()

t1 = threading.Thread(target=runOne, args = ('one',))
t1.start()

t2 = threading.Thread(target=runOne, args = ('two',))
t2.start()

t1 = threading.Thread(target=runOne, args = ('three',))
t1.start()

t2 = threading.Thread(target=runOne, args = ('four',))
t2.start()

t1 = threading.Thread(target=runOne, args = ('five',))
t1.start()

time.sleep(20)

Kyle Benzo

unread,
May 19, 2014, 6:44:17 PM5/19/14
to blaz...@googlegroups.com
Michael,

Are you running this on Windows or Linux (or something else)? The five windows are opening and connecting to the appropriate ip:port but all of the fill_field,send_enter get passed to the first window. I was thinking maybe this works fine on Linux but perhaps needs a different control port for each instance when done on windows?

Thanks,
Kyle

Randy Syring

unread,
May 19, 2014, 7:12:09 PM5/19/14
to blaz...@googlegroups.com
Kyle,

Yes, that's a good point.  The wc3270App uses a socket connection to the executable to control it, unlike Linux.  Each one of those executables will need to listen on a different port:

https://bitbucket.org/rsyring/py3270/src/tip/py3270/__init__.py?at=default#cl-144

I'd suggest creating a wc3270App instance per thread, with it's own unique socket port, and feed that to your Emulator() instance for the "app" parameter. 

Also, FYI, py3270 has not been used much on Windows.  Please let me know what your results are.


Randy Syring
Husband | Father | Redeemed Sinner

"For what does it profit a man to gain the whole world
and forfeit his soul?" (Mark 8:36 ESV)


Michael Potter

unread,
May 19, 2014, 7:15:30 PM5/19/14
to blaz...@googlegroups.com
Kyle, 
This sounds like an interesting problem.
Please post your successful example back on this issue so we can all learn from it.

Thanks,


--
You received this message because you are subscribed to a topic in the Google Groups "BlazeLibs" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/blazelibs/7m33qL-bPos/unsubscribe.
To unsubscribe from this group and all its topics, send an email to blazelibs+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Michael Potter
  Tapp Solutions, LLC
  Replatform Technologies, LLC
+1 770 815 6142  ** Atlanta ** mic...@potter.name  **  www.linkedin.com/in/michaelpotter

Kyle Benzo

unread,
May 20, 2014, 5:10:04 PM5/20/14
to blaz...@googlegroups.com, mic...@potter.name
Alright I got it to work. I made the following changes to __init__.py for py3270

class wc3270App(ExecutableApp):
    executable = 'wc3270.exe'
    # see notes for args in x3270App
    args = ['-xrm', 'wc3270.unlockDelay: False']

    def __init__(self, script_port=17938):
        self.sp = None
        self.socket_fh = None
        self.script_port = script_port

And I used the following code to invoke several instances

def worker(num):
    """worker function"""
    wc1 = wc3270App(script_port=num)
    em = Emulator(visible=True,app=wc1)
    em.connect('170.2.8.90:5023')
    em.fill_field(18, 17, username, 8)
    em.fill_field(19, 17, password, 8)
    em.send_enter()
    em.fill_field(6, 2, 's', 1)
    em.send_enter()
    return

if __name__ == '__main__':
    jobs = []
    for i in range(17938, 17945):
        p = multiprocessing.Process(target=worker, args=(i,))
        jobs.append(p)
        p.start()


Thanks guys,
Kyle

charbel rajeh

unread,
Oct 21, 2020, 8:09:04 PM10/21/20
to BlazeLibs
Hi there , the same problem happends to me too .
all the fill_fields , send_enters get passed only to the first_window..
Is there a way to make that's work using the same port? ( im using windows not linux)

Thanks!
Reply all
Reply to author
Forward
0 new messages