web-dev-qa-db-fra.com

Python Écoute de socket

Tout ce qui est mentionné ci-dessous est sur les machines Windows utilisant python 2.7

Bonjour,

J'essaie actuellement d'écouter sur un socket les données envoyées par un programme distant. Ces données sont ensuite imprimées à l'écran et une entrée utilisateur est demandée qui est ensuite retournée au programme distant. Lors des tests, j'ai pu demander au programme distant de m'envoyer un menu de programmes en ligne de commande (cmd, ipconfig, whoami, ftp), puis mon programme revient avec un nombre comme sélection de l'option de menu.

Le programme distant reçoit ma réponse et envoie la sortie de la commande sélectionnée. ipconfig et whoami fonctionnent parfaitement, mais cmd et ftp ne renvoient la sortie du terminal qu'une seule fois. (C'est-à-dire que je peux entrer une commande dans le programme FTP et l'envoyer aussi au programme distant avant de ne plus jamais l'entendre)

La partie de mon code qui échoue est que if ready[0]: n'est jamais prêt une deuxième fois après la première conversation.

Je sais que le programme distant fonctionne correctement car je peux utiliser netcat pour remplacer mon code et faire fonctionner indéfiniment le terminal cmd.

Comment procéder pour implémenter correctement un écouteur de socket python qui peut prendre en compte ce type de connexion?

Mon "programme" dans son intégralité:

import socket, sys, struct, time, select

Host = ''
port = 50000
connectionSevered=0

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
    print 'Failed to create socket'
    sys.exit()
print '[+] Listening for connections on port '+str(port)+'.'

s.bind((Host,port))
s.listen(5)         

def recvall(the_socket,timeout=2):
    global connectionSevered
    data='';          # Data found by recv
    total_data=[];    # Finally list of everything

    s.setblocking(0)  #make socket non blocking
    begin=time.time() #beginning time

    while 1:
        ready = select.select([client], [], [], .2)
        if time.time()-begin > timeout:
            print 'Timeout reached'
            #Leave loop, timer has reached its threshold
            break
        if ready[0]:
            print 'In ready loop!'
            try:
                data = client.recv(4096)    #attempt to fetch data
                if data:
                    begin=time.time()       #reset timeout timer
                    total_data.append(data) 
                    data='';
            except socket.error:
                print '[+] Lost connection to client. Printing buffer...'
                connectionSevered=1   # Let main loop know connection has errored
                pass
        time.sleep(1)
    #join all parts to make final string
    return ''.join(total_data)

client, address = s.accept()
print '[+] Client connected!'

while (connectionSevered==0): # While connection hasn't errored
    print "connectionSevered="+str(connectionSevered) # DEBUG
    recvall(s)
    response = raw_input()                  #take user input
    client.sendto(response)                   #send input
client.close(0)

Veuillez me faire savoir si vous avez besoin de plus d'informations, toute aide serait grandement appréciée, je suis très nouveau dans ce domaine et désireux d'apprendre.

11
Mr S

Jouer avec cela pendant un certain temps l'a finalement fait fonctionner Nice avec une session telnet localement en utilisant python 2.7.

Ce qu'il fait, c'est qu'il configure un thread qui s'exécute lorsque le client se connecte en écoutant les informations du client.

Lorsque le client envoie un retour ("\ r\n" devra peut-être changer cela si vous interagissez avec un système Linux?) Le message est imprimé sur le serveur, alors que cela se produit s'il y a une entrée brute côté serveur cette sera envoyé au client:

import socket
import threading
Host = ''
port = 50000
connectionSevered=0

class client(threading.Thread):
    def __init__(self, conn):
        super(client, self).__init__()
        self.conn = conn
        self.data = ""
    def run(self):
        while True:
            self.data = self.data + self.conn.recv(1024)
            if self.data.endswith(u"\r\n"):
                print self.data
                self.data = ""

    def send_msg(self,msg):
        self.conn.send(msg)

    def close(self):
        self.conn.close()

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((Host,port))
    s.listen(5)
except socket.error:
    print 'Failed to create socket'
    sys.exit()

print '[+] Listening for connections on port: {0}'.format(port)


conn, address = s.accept()
c = client(conn)
c.start()
print '[+] Client connected: {0}'.format(address[0])
c.send_msg(u"\r\n")
print "connectionSevered:{0}".format(connectionSevered) 
while (connectionSevered==0):
    try:
        response = raw_input()  
        c.send_msg(response + u"\r\n")
    except:
        c.close()

La réponse ci-dessus ne fonctionnera pas pour plus d'une seule connexion. Je l'ai mis à jour en ajoutant un autre fil pour prendre des connexions. Il est désormais possible de connecter plusieurs utilisateurs.

import socket
import threading
import sys
Host = ''
port = 50000

class client(threading.Thread):
    def __init__(self, conn):
        super(client, self).__init__()
        self.conn = conn
        self.data = ""

    def run(self):
        while True:
            self.data = self.data + self.conn.recv(1024)
            if self.data.endswith(u"\r\n"):
                print self.data
                self.data = ""

    def send_msg(self,msg):
        self.conn.send(msg)

    def close(self):
        self.conn.close()

class connectionThread(threading.Thread):
    def __init__(self, Host, port):
        super(connectionThread, self).__init__()
        try:
            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.s.bind((Host,port))
            self.s.listen(5)
        except socket.error:
            print 'Failed to create socket'
            sys.exit()
        self.clients = []

    def run(self):
        while True:
            conn, address = self.s.accept()
            c = client(conn)
            c.start()
            c.send_msg(u"\r\n")
            self.clients.append(c)
            print '[+] Client connected: {0}'.format(address[0])



def main():
    get_conns = connectionThread(Host, port)
    get_conns.start()
    while True:
        try:
            response = raw_input() 
            for c in get_conns.clients:
                c.send_msg(response + u"\r\n")
        except KeyboardInterrupt:
            sys.exit()

if __name__ == '__main__':
    main()

Les clients ne peuvent pas voir ce que disent les autres clients, les messages du serveur seront envoyés à tous les clients. Je vais laisser cela comme un exercice pour le lecteur.

13
Noelkd

Si vous êtes dans Python 3 maintenant et que vous vous interrogez toujours sur les sockets, voici une façon simple de les utiliser:

server.py

import time
import socket

# creating a socket object
s = socket.socket(socket.AF_INET,
                  socket.SOCK_STREAM)

# get local Host machine name
Host = socket.gethostname() # or just use (Host == '')
port = 9999

# bind to pot
s.bind((Host, port))

# Que up to 5 requests
s.listen(5)

while True:
    # establish connection
    clientSocket, addr = s.accept()
    print("got a connection from %s" % str(addr))
    currentTime = time.ctime(time.time()) + "\r\n"
    clientSocket.send(currentTime.encode('ascii'))
    clientSocket.close()

client.py

import socket

# creates socket object
s = socket.socket(socket.AF_INET,
                  socket.SOCK_STREAM)

Host = socket.gethostname() # or just use (Host = '')
port = 9999

s.connect((Host, port))

tm = s.recv(1024) # msg can only be 1024 bytes long

s.close()
print("the time we got from the server is %s" % tm.decode('ascii'))

Exécutez d'abord server.py, puis exécutez client.py

C'est juste recevoir et envoyer le currentTime.

Quoi de neuf dans les Python 3.4?

Une différence majeure entre les sockets python 2.7 et python 3.4) réside dans l'envoi de messages. Vous devez .encode() (en utilisant généralement 'ascii' ou vide comme paramètres/arguments) puis en utilisant .decode()

Par exemple, utilisez .encode() pour envoyer et utilisez .decode() pour recevoir.

Informations supplémentaires: tutoriel socket client/serveur

6
Leigh Flix