IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Réseau/Web Python Discussion :

Serveur TCP multi-thread


Sujet :

Réseau/Web Python

  1. #1
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2012
    Messages
    359
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 359
    Points : 738
    Points
    738
    Billets dans le blog
    2
    Par défaut Serveur TCP multi-thread
    Bonjour,

    je tente d'écrire un serveur TCP multi-thread qui ne semble pas répondre et je ne trouve pas d'ou ca vient.
    Quelqu'un a t-il une meilleure vu que moi ?

    Le serveur:
    TCPy.py

    Son instanciassion:
    test.py

    Le client:
    test_client.py
    Le gourou dicte la ligne (de commande) à suivre ...

    Penser à lire le Tutoriel Batch ou a consulter la FAQ Batch et ses contributions,
    ainsi que le Cour sur la ligne de commande et des scripts

  2. #2
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2012
    Messages
    359
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 359
    Points : 738
    Points
    738
    Billets dans le blog
    2
    Par défaut
    Re

    J'avais oublier le return False dans la fonction onMessage mais il n'y a pas que cela

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
     
    #import pickle
    #import time
     
    from TCPy import TCPyServer
    import socket
     
    class BasicServer(TCPyServer):
        def __init__(self, family, interface, port, clientmax, verbosity, confFile):
            TCPyServer.__init__(self, family, interface, port, clientmax, verbosity, confFile)
     
        def onMessage(self, client, addr, message):
            print "Client Sent Message\0"
            #Sending message to all clients
            self.sendMessage(message + "\0")
            return False
     
        def onOpen(self, client, addr):
            print "Client Connected"
     
        def onClose(self, client, addr):
            print "Client Disconnected"
     
    def main():
        server = BasicServer(socket.AF_INET, "192.168.1.15", 20320, 16, 1, "")
        while 1:
            pass
     
    if __name__ == "__main__":
        main()
    Dur journée au travail ...
    Le gourou dicte la ligne (de commande) à suivre ...

    Penser à lire le Tutoriel Batch ou a consulter la FAQ Batch et ses contributions,
    ainsi que le Cour sur la ligne de commande et des scripts

  3. #3
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2012
    Messages
    359
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 359
    Points : 738
    Points
    738
    Billets dans le blog
    2
    Par défaut
    Et deux erreurs de moins ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    #!/usr/bin/python
    # *-* coding: utf-8 *-*
     
    def testmod(modname):
        """
        Check if module has been effectively imported.
     
        @param:     modname     string      Name of module
        @return:    True/False  boolean     Return True if module has been
                                            imported, False otherwise
        """
        if modname not in sys.modules:
            return False
        return True
     
    import sys                                                                      # Import system interfcace
    import os                                                                       #
    import time                                                                     # Import time module for time.time() (wait a time using task scheduler)
    import socket                                                                   # Import socket for TCP socket support
    import select                                                                   # Import select for non-blocking connection/error handlelling
    import errno                                                                    #
     
    # Import low-level and high-level threading interface
    if sys.version_info[0] >= 3:
        from _thread import *                                                       # Use _thread module instead thread module for python 3 and highter
        from threading import *                                                     # Import Thread(), Lock()
    else:
        from thread import *
        ############################################################################# Import Thread(), Lock()
        if not testmod("thread"):
            from dummy_threading import *                                           # Use dummy_threading if thread module is missing for python 2.x and lower
        else:
            from threading import *                                                 # Otherwise use threading
     
    TCPyVersMajor = 1                                                               # Server major version
    TCPyVersMinor = 3                                                               # Server minor version
    TCPyVersBuild = 0                                                               # Server build version
     
     
    class TCPyServer(Thread):
        ############################################################################# Private attributes
        __conf = {
            "console":  [                                                           # Console data
                None,                                                               #   Console socket
                {
                    "ifFamily":     socket.AF_INET,                                 #     Console interface family
                    "iface":        "127.0.0.1",                                    #     Console interface name
                    "port":         49153,                                          #     Console TCP port
                    "clientMax":    1                                               #     Console client maximum connection
                },                                                                  #   Console configuration
                None,                                                               #   Console thread object
                None                                                                #   Console event object
            ],
            "server":   [                                                           # Server data
                None,                                                               #   Server socket
                {
                    "ifFamily":     socket.AF_INET,                                 #     Server interface family
                    "iface":        "",                                             #     Server interface name
                    "port":         49152,                                          #     Server TCP port
                    "clientMax":    16,                                             #     Server client maximum connection
                    "verbosity":    True                                            #     Server output mode (quiet/verbose)
                },                                                                  #   Server configuration
                None,                                                               #   Server thread object
                None                                                                #   Server event object
            ]
        }
        __isRunning = False                                                         # Server state
        __listenerList = []                                                         # Listener socket list
        __erroredList = []                                                          # Pontently errored socket list
        __clientList = []                                                           # Client List
        __lock_isRunning = Lock()                                                   # Lock on server state
        __lock_listenerList = Lock()                                                # Lock on listener socket list
        __lock_erroredList = Lock()                                                 # Lock on pontently errored socket list
        __lock_clientList = Lock()                                                  # Lock on client list
        ############################################################################# Public attributes
        # ***** No pubic attribute
     
     
        ############################################################################# Private method
        def __init__(self, ifFamily = socket.AF_INET, iface = "", port = 49152, clientMax = 16, verbosity = True, confFile = "./TCPyServer.conf"):
            """
            Instantiate the TCPyServer object in a separate thread.
     
            @param:     ifFamily        integer     Socket family, use socket.AF_ contant
            @param:     iface           string      Interface Name, e.g.: IP address or host name
            @param:     port            integer     TCP service port
            @param:     clientMax       integer     Client maximum connection
            @param:     verbosity       boolean     Verbose or quiet mode
            @param:     confFile        string      Server configuration file
            @return:    Server thread object or None if error occur
            """
            _name = "TCPySerever"                                                   # Proccess name
            Thread.__init__(self, name = _name)                                     # Set TCPyServer run in own thread
            self.daemon = True                                                      # Set this thread is a daemonic-thread
            if os.path.isfile(confFile):                                            # If configuration exist
                pass                                                                #   Load parameter from there
            else:                                                                   # Else use call parameters
                self.__conf["server"][1]["ifFamily"] = ifFamily                     #
                self.__conf["server"][1]["iface"] = iface                           #
                self.__conf["server"][1]["port"] = port                             #   Private TCP port are in range 49152–65535
                self.__conf["server"][1]["clientMax"] = clientMax                   #
                self.__conf["server"][1]["verbosity"] = verbosity                   #
            try:                                                                    # Try to
                self.start()                                                        #   Start thread
            except:                                                                 # Caugth all error if occur
                return None                                                         #   And return None object to caller
     
        def run(self):
            self.__debug("[-] TCPyServer daemon thread started")                    # Print start message on output
            llst = self.__listenerList
            llck = self.__lock_listenerList
            elst = self.__erroredList
            elck = self.__lock_erroredList
            clst = self.__clientList
            clck = self.__lock_clientList
            for listener in ("console", "server"):                                  # For all listener
                self.__startListener(listener)                                      #   Start listener
            self.__isRunning = True                                                 # Set server is running
            while self.__isRunning:                                                 # While server is running
                try:
                    (rsock, wsock, esock) = select.select(llst, [], elst)           #   Check current state of all socket
                    for s in esock:                                                 #   Foreach socket is errored
                        if s is self.__conf["console"][0]:
                            name = "console"
                        else:
                            name = "server"
                        self.__restartListener(name)                                #     Restart socket
                        pass
                    for s in rsock:                                                 #   Foreach socket is readable
                        (csock, caddr) = s.accept()                                 #     Accept connection on current socket
                        m = "[-] Accept incomming transmission from {}:{}"
                        self.__debug(m.format(caddr[0], str(caddr[1])))
                        (cargs) = (csock, caddr)                                    #     Created argument list for client thread
                        self.__addList(elst, elck, csock)                           #     Add client socket to erroredList
                        if s is self.__conf["server"][0]:                           #     If the current socket is server socket
                            clt = (csock, caddr, None, None)                        #       Created client record in form (client socket, client address, client thread, client event)
                            self.__addList(clst, clck, clt)                         #       Add client record to clienList
                        start_new_thread(self.__serveAppLayer, (cargs))             #       Start session in new thread
                except socket.error as e:
                    m = "[x] {}"
                    if type(e) == str:
                        m = m.format(e)
                    elif type(e) is tuple:                                          #   Else if e is tuple
                        (err, msg) = e.args                                         #     Get errno and strerror()
                        if (err == errno.EAGAIN                                     #     If timeout occur before operation was finished
                            or err == errno.EWOULDBLOCK                             #     or the operation would block on non-blocking socket
                            or err == errno.EINTR):                                 #     or an interrupt occur before data are available
                            continue                                                #       Non-fatal error, just waiting at end of loop
                        else:                                                       #   Else a fatal error occur
                            strerror = "Code={}, Msg={}".format(e.args)
                            m = m.format(strerror)                                  #     Format error message with error code and error string
                    self.__debug(m)
                    break
                except RuntimeError as e:
                    self.__debug(e)
                    break
                except:
                    m = "[x] Unexpected error: {}".format(sys.exc_info()[0])
                    self.__debug(m)
                    break
                time.sleep(0.1)                                                     #   Wait 100ms before continue loop
            self.__stopListener("console")                                          # Stop console listener
            self.__stopListener("server")                                           # Stop server listener
            self.__debug("[-] TCPyServer daemon thread stopped")
     
        def __debug(self, msg):
            """
            Print debugging information if verbosity initilisation parameter's is
            set to True
     
            @param:     msg         string              Message to be printed
            """
            if self.__conf["server"][1]["verbosity"]:                               # If in verbose mode:
                print msg                                                           #   print messeage.
     
        def __printVersion(self):
            """
            Print version information
     
            @param:     msg         string              Message to be printed
            """
            print "TCPyServer v{}.{}.{}".format(str(TCPyVersMajor), str(TCPyVersMinor), str(TCPyVersBuild))
     
        def __P(self, lock):
            """
            Semaphore-like P() function
     
            @param:     lock        Lock() object       Lock to be acquire
            """
            haveLock = False
            while not haveLock:                                                     # While the current thread haven't lock:
                    if not (lock).acquire(True):                                    #   if not acquire lock:
                        time.sleep(0.005)                                           #     wait 5ms for retry
                    else:                                                           #   else
                        haveLock = True                                             #     set lock is acquired
     
        def __V(self, lock):
            """
            Semaphore-like V() function
     
            @param:     lock        Lock() object       Lock to be release
            """
            try:
                (lock).release()                                                    # Release lock
            except ThreadError as e:
                m = "[x] The current lock already release: {}".format(e)
                raise RuntimeError(m)
     
        def __addList(self, lst, lck, data):
            """
            Add data to protected list
     
            @param:     lst         list                List to be update
            @param:     lck         Lock() object       Lock on list
            @param:     data        Lock() Object       Data to be append
            """
            try:                                                                    # Try to
                self.__P(lck)                                                       #   Acquire lock
                lst.append(data)                                                    #   Add data to list
                self.__V(lck)                                                       #   Release lock
            except e:                                                               # If an error occur
                raise RuntimeError(e)                                               #   Reraise as RuntimeError
     
        def __delList(self, lstr, lck, data):
            """
            Delete data from protected list
     
            @param:     lst         list                List to be update
            @param:     lck         Lock() object       Lock on list
            @param:     data        Lock() Object       Data to be remove
            """
            try:                                                                    # Try to
                self.__P(lck)                                                       #   Acquire lock
                lst.remove(data)                                                    #   Add data to list
                self.__V(lck)                                                       #   Release lock
            except e:                                                               # If an error occur
                raise RuntimeError(e)                                               #   Reraise as RuntimeError
     
        def __startListener(self, name):
            """
            Start listener
     
            @param:     name        string          Listener name
            """
            ifFamily = self.__conf[name][1]["ifFamily"]
            iface = self.__conf[name][1]["iface"]
            port = self.__conf[name][1]["port"]
            clientMax = self.__conf[name][1]["clientMax"]
            elst = self.__erroredList
            elck = self.__lock_erroredList
            llst = self.__listenerList
            llck = self.__lock_listenerList
            try:                                                                    # Try to
                self.__conf[name][0] = socket.socket(ifFamily, socket.SOCK_STREAM)  #   Open socket
                self.__debug("[-] {} socket opened".format(name))                   #
                (self.__conf[name][0]).setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    #   Define socket options
                self.__debug("[-] {} socket configured".format(name))               #
                (self.__conf[name][0]).bind((iface, port))                          #   Bind interface and port
                self.__debug("[-] {} bound to {}:{}".format(name, iface, str(port)))#
                (self.__conf[name][0]).listen(clientMax)                            #   Listen connection
                self.__debug("[-] {} listen {}:{}".format(name, iface, str(port)))  #
                self.__addList(elst, elck, self.__conf[name][0])                    #   Add current listener socket to potently errored socket list
                self.__addList(llst, llck, self.__conf[name][0])                    #   Add current listener socket to potently readable socket list
                if name == "server":                                                #   If the current listener is the server
                    self.onStart()                                                  #     Call user fucntion onStart() for start application layer
            except socket.error as e:                                               # If an error (e) occurs on socket
                if type(e) is str:                                                  #   If e is string
                    raise RuntimeError("[x] {}".format(e))                          #     Raise exception with e as message
                elif type(e) is tuple:                                              #   Else if e is tuple
                    err, msg = e.args                                               #     Set err to errno and msg to strerror()
                    if (err == errno.EAGAIN                                         #     If timeout occur before operation was finished
                        or err == errno.EWOULDBLOCK                                 #     or the operation would block on non-blocking socket
                        or err == errno.EINTR):                                     #     or an interrupt occur before data are available
                        # Fermer le socket
                        return False                                                #       Non-fatal error
                    else:                                                           #   Else a fatal error occur
                        m = "[x] Code: {}, Msg: {}".format(str(err), msg)           #     Set m with error message
                        raise RuntimeError(m)                                       #     Reraise as RuntimeError
            except RuntimeError as e:                                               # If a runtime error occur
                raise RuntimeError(e)                                               #   Reraise
            except:                                                                 # If an unexcepted error occur (assumed as fatal)
                m = "[x] Unexpected error: {}".format(sys.exc_info()[0])            #   Set m with error message
                raise RuntimeError(m)                                               #   Reraise as RuntimeError
            return True
     
        def __stopListener(self, name):
            """
            Stop listener
     
            @param:     name        string          Listener name
            """
            try:                                                                    # Try to
                (self.__conf[name][0]).shutdown(SHUT_RD)                            #   Disallow receive data on listener socket
                if name == "server":                                                #   If listener is the server
                    self.__isRunning = Fasle                                        #     Set server is down
                self.__delList(elst, elck, self.__conf[name][0])                    #   Delete current listener socket to potently errored socket list
                self.__delList(llst, llck, self.__conf[name][0])                    #   Delete current listener socket to potently readable socket list
                if name == "server":                                                #   If listener is the server
                    self.onStop()                                                   #     Call user fucntion onStop() for shutdown application layer
                (self.__conf[name][0]).close()                                      #   Close listener socket
            except socket.error as e:                                               # If an error (e) occurs on socket
                if type(e) is str:                                                  #   If e is string
                    raise RuntimeError("[x] {}".format(e))                          #     Raise exception with e as message
                elif type(e) is tuple:                                              #   Else if e is tuple
                    err, msg = e.args                                               #     Set err to errno and msg to strerror()
                    if (err == errno.EAGAIN                                         #     If timeout occur before operation was finished
                        or err == errno.EWOULDBLOCK                                 #     or the operation would block on non-blocking socket
                        or err == errno.EINTR):                                     #     or an interrupt occur before data are available
                        # Fermer le socket
                        return False                                                #       Non-fatal error
                    else:                                                           #   Else a fatal error occur
                        m = "[x] Code: {}, Msg: {}".format(str(err), msg)           #     Set m with error message
                        raise RuntimeError(m)                                       #     Reraise as RuntimeError
            except RuntimeError as e:                                               # If a runtime error occur
                raise RuntimeError(e)                                               #   Reraise
            except:                                                                 # If an unexcepted error occur (assumed as fatal)
                m = "[x] Unexpected error: {}".format(sys.exc_info()[0])            #   Set m with error message
                raise RuntimeError(m)                                               #   Reraise as RuntimeError
            return True
     
        def __restartListener(self, name):
            """
            Restart listener
     
            @param:     name        string          Listener name
            """
            try:                                                                    # Try to
                if name == "server":                                                #   If listener is the server
                    self.onRestart(1)                                               #     Call user fucntion onRestart() for first pass of application layer restart
                # Traiter l'erreur dans __stopListener
                self.__stopListener(name)                                           #   Stop server
                if name == "server":                                                #   If listener is the server
                    self.onRestart(2)                                               #     Call user fucntion onRestart() for second pass of application layer restart
                # Traiter l'erreur dans __startListener
                self.__startListener(name)                                          #   Start server
                if name == "server":                                                #   If listener is the server
                    self.onRestart(3)                                               #     Call user fucntion onRestart() for thrid pass of application layer restart
            except e:                                                               # If an error occur
                raise RuntimeError(e)                                               #   Reraise as RuntimeError
     
        def __serveAppLayer(self, csock, caddr):
            """
            Serve user-define applicayion layer
     
            @param:     csock       socket object       Client socket
            @param:     caddr       Iface addr object   Client address
            """
            ip = caddr[0]
            port = caddr[1]
            lstc = self.__clientList
            lckc = self.__lock_clientList
            lste = self.__erroredList
            lcke = self.__lock_erroredList
            post = "[-] Client thread ({})".format(self.name)
            popen = "[-] Client connection successfuly opened for {}:{}"
            pmsg = "[-] Incomming client message from {}:{}: {}"
            pclose = "[-] Client connection successfuly closed for {}:{}"
            self.__debug("{} created for {}:{}".format(post, ip, str(port)))        # Print the start of client thread on output
            try:                                                                    # Try to
                self.__debug(popen.format(ip, str(port)))                           #
                if csock is not self.__conf["console"][0]:                          #   If client socket isn't linked to console
                    self.onOpen(csock, caddr)                                       #     Call user define onOpen() function for application layer connection setup
                inSession = True                                                    #   Set client start current session
                while inSession:                                                    #   While they have one message to be read
                    msg = self.__receiveMessage(csock, caddr)                       #     Read message
                    if csock is not self.__conf["console"][0]:                      #     If client socket isn't linked to console
                        inSession = self.onMessage(csock, caddr, msg)               #       Call user define onMessage(msg) function for application layer message proccessing
                    else:                                                           #     Else
                        inSession = self.__consoleMessage(csock, caddr, msg)        #       Call console proccessing function
                    self.__debug(pmsg.format(ip, str(port), msg))                   #     Print trace of message
                if csock is not self.__conf["console"][0]:                          #   If client socket isn't linked to console
                    self.onClose(csock, caddr)                                      #     Call user define onClose() function for application layer connection shutdown
                self.__debug(pclose.format(ip, str(port)))                          #
            except Exception as e:                                                  # If an exception occur (for support application layer exception)
                # Fermer le socket
                m = "[x] Exception occurs in __receiveMessage() from {}:{}: {}"     #   Construct error message
                if type(e) is str:                                                  #   If e is string
                    m = m.format(ip, str(port), e)                                  #     Format error message with string
                elif type(e) is tuple:                                              #   Else if e is tuple
                    err, msg = e.args                                               #     Get errno and strerror()
                    m = m.format(ip, str(port), "Code={}, Msg={}".format(err, msg)) #     Format error message with error code and error string
                raise RuntimeError(m)                                               #   Reraise as RuntimeError
            except:                                                                 # If an unexcepted error occur (assumed as fatal)
                # Fermer le socket
                m = "[x] Unexpected error: {}".format(sys.exc_info()[0])            #   Set m with error message
                raise RuntimeError(m)                                               #   Reraise as RuntimeError
            finally:
                csock.shutdown()
                csock.close()
                self.__delList(lstc, lckc, (csock, caddr),)                         #   Delete client to clientList
                self.__delList(lste, lcke, csock)                                   #   Delete client socket to erroredList
            self.__debug("{} terminated".format(post))                              # Print the end of client thread on output
     
        def __receiveMessage(self, csock, caddr):
            """
            Receive message from client
     
            @param:     csock       socket object       Client socket
            @param:     caddr       Iface addr object   Client address
            """
            chunks = []                                                             # List of received chunk
            while (True):                                                           # While message isn't fully receive (or error occurs)
                (sr, sw, se) = select.select([csock], [], [csock])                  #   Check if client socket is readable or errored
                s = (se, sr)                                                        #   Set s as tuple in form (errored socket, readable socket)
                i = 0                                                               #   Set i to 0
                while (i < 2):                                                      #   Foreach socket list
                    if (s[i]):                                                      #     If socket list isn't an empty tuple
                        try:                                                        #       Try to
                            if not i:                                               #         If proccessing on errored socket
                                (s[i][0]).recv(1, socket.MSG_DONTWAIT)              #           Receive message in non-blocking mode for raise exception
                            else:                                                   #         Else
                                chunk = (s[i][0]).recv(4096)                        #           Read 4096 characters on socket
                                if not chunk or len(chunk) == 0:                                       #           If chunk is an empty string (end of message)
                                    return b''.join(chunks)                         #             Concatenate chunks and return message
                                chunks.append(chunk)                                #           Append current chunk to chunk list
                        except socket.error as e:                                   #       If an error occurs on socket
                            if type(e) is str:                                      #         If e is string
                                raise RuntimeError(e)                               #           Reraise as RuntimeError
                            elif type(e) is tuple:                                  #         Else if e is tuple
                                err, msg = e.args                                   #           Set err to errno and msg to strerror()
                                err = str(err)                                      #           Cast err in string
                                if (err == errno.EAGAIN                             #           If timeout occur before data was received
                                    or err == errno.EWOULDBLOCK                     #           or the operation would block on non-blocking socket
                                    or err == errno.EINTR):                         #           or an interrupt occur before data are available
                                    continue                                        #             Non-fatal error, just waiting at end of loop
                                else:                                               #           Else a fatal error occur
                                    m = "[x] Code: {}, Msg: {}".format(err, msg)    #             Set m with error message
                                    raise RuntimeError(m)                           #             Reraise as RuntimeError
                        except:                                                     #         If an unexcepted error occur
                            m = "[x] Unexpected error: {}".format(sys.exc_info()[0])#           Set m with error message
                            raise RuntimeError(m)                                   #           Reraise as RuntimeError
                time.sleep(0.1)                                                     #   Wait 100ms before continue loop
     
        def __sendMessage(self, csock, caddr, msg):
            """
            Send message to client
     
            @param:     csock       socket object       Client socket
            @param:     caddr       Iface addr object   Client address
            @param:     msg         String              Message to be sent to client
            """
            totalsent = 0                                                           # Total of byte sent on socket
            msglen = len(msg)                                                       # Lenght of message
            #csock = client[0]                                                      # Client socket
            while totalsent < msglen:                                               # While they have a chunk of message to be write
                try:                                                                # Try to
                    (rsock, wsock, esock) = select.select([], [csock], [csock])     #   Check if socket is errored or writable
                    if esock:                                                       #   If socket is errored
                        esock.recv(1, socket.MSG_DONTWAIT)                          #     Receive message in non-blocking mode for raise exception
                    elif wsock:                                                     #   Else if socket is writable
                        sent = csock.send(msg[totalsent:])                          #     Send next chunk
                        if sent == 0:                                               #     If no data has been sent
                            raise RuntimeError("[x] socket connection broken")      #       Raise RuntimeError
                        totalsent = totalsent + sent                                #     Add sent chunk lenght to total of byte sent on socket
                except socket.error as e:                                           # If an error occurs on socket
                    if type(e) is str:                                              #   If e is string
                        raise RuntimeError(e)                                       #     Reraise as RuntimeError
                    elif type(e) is tuple:                                          #   Else if e is tuple
                        err, msg = e.args                                           #     Set err to errno and msg to strerror()
                        err = str(err)                                              #     Cast err in string
                        if (err == errno.EAGAIN                                     #     If timeout occur before data was received
                            or err == errno.EWOULDBLOCK                             #     or the operation would block on non-blocking socket
                            or err == errno.EINTR):                                 #     or an interrupt occur before data are available
                            continue                                                #       Non-fatal error, just waiting at end of loop
                        else:                                                       #     Else a fatal error occur
                            m = "[x] Code: {}, Msg: {}".format(err, msg)            #       Set m with error message
                            raise RuntimeError(m)                                   #       Reraise as RuntimeError
                except:                                                             #     If an unexcepted error occur
                    m = "[x] Unexpected error: {}".format(sys.exc_info()[0])        #       Set m with error message
                    raise RuntimeError(m)                                           #       Reraise as RuntimeError
            return totalsent
     
        def __broadcastMessage(self):
            pass
     
     
        ############################################################################# Public method (exec only, if overwrite private function cannot be call)
        def sendMessage(self, csock, caddr, msg):
            """
            Send message to client
     
            @param:     csock       socket object       Client socket
            @param:     caddr       Iface addr object   Client address
            @param:     msg         String              Message to be sent to client
            """
            return self.__sendMessage(csock, caddr, msg)
     
        def broadcastMessage(self, msg):
            """
            Send message to all client
     
            @param:     msg         String              Message to be sent to all client
            """
            return self.__broadcastMessage(msg)
     
     
        ############################################################################# Public method (exec/overwrite)
        def onStart(self):
            """
            User define function called when console and server sockets are
            in listenning, and before enter in accept/error proceessing loop.
            """
            pass
     
        def onStop(self):
            """
            User define function called before stop server/console sockets.
            """
            pass
     
        def onRestart(self, index):
            """
            User define function called when console/server sockets are
            restarted.
     
            @param:     index       integer         Current restart state:
                                                    1   before stop server/console socket
                                                    2   after stop server/console socket
                                                        and before restart there
                                                    3   after restart server/console socket
            """
            pass
     
        def onOpen(self, csock, caddr):
            """
            User define function called when client connection is opened.
     
            @param:     csock       socket object       Client socket
            @param:     caddr       Iface addr object   Client address
            """
            pass
     
        def onMessage(self, csock, caddr):
            """
            User define function called when receive client message.
            Implement application protocol there.
     
            @param:     csock       socket object       Client socket
            @param:     caddr       Iface addr object   Client address
            """
            pass
     
        def onClose(self, csock, caddr):
            """
            User define function called when client connection is closed.
     
            @param:     csock       socket object       Client socket
            @param:     caddr       Iface addr object   Client address
            """
            pass
    Le gourou dicte la ligne (de commande) à suivre ...

    Penser à lire le Tutoriel Batch ou a consulter la FAQ Batch et ses contributions,
    ainsi que le Cour sur la ligne de commande et des scripts

  4. #4
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je crains de ne pas avoir le courage d'éplucher les plus de 500 lignes de ton code, et comme je n'ai plus Python 2, je ne pourrai même pas l'essayer. Mais effectivement, il est très bien présenté, et ça représente un sacré boulot.

    Cependant, il me semble qu'avec le seul module socket + threading, tu te compliques bien la vie. En effet, il existe un autre module "SocketServeur" ("socketserveur" en Python 3) qui permet de faire des serveurs TCP avec des threads ou des processus, c'est à dire qui n'ont pas à terminer le traitement d'une requête pour accepter la suivante.

    Je m'étais penché sur la question en ...2008, et c'était justement en Python 2. Voir ici en guise de source d'inspiration: http://python.jpvweb.com/python/mesr...eur_tcp_stream.

    Ce n'est qu'un petit code de principe, et il n'a pas l'ambition de ton projet, mais il marchait très bien quand je l'ai fait.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

Discussions similaires

  1. réseau TCP multi-threading
    Par khalil15 dans le forum Entrée/Sortie
    Réponses: 2
    Dernier message: 22/11/2019, 17h09
  2. serveur préthreadé / multi threadé
    Par lecluc dans le forum C#
    Réponses: 1
    Dernier message: 09/03/2011, 13h28
  3. serveur TCP multi-clients threadé
    Par phobos64 dans le forum Réseau
    Réponses: 10
    Dernier message: 28/05/2009, 21h22
  4. Réponses: 1
    Dernier message: 17/11/2006, 23h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo