web-dev-qa-db-ja.com

Pythonソケットリスニング

以下のすべてはpython 2.7を使用するWindowsマシン上にあります

こんにちは、

私は現在、リモートプログラムによるデータ送信をソケットでリッスンしようとしています。次に、このデータが画面に出力され、ユーザー入力が要求されて、リモートプログラムに返されます。テストでは、リモートプログラムからコマンドラインプログラム(cmd、ipconfig、whoami、ftp)のメニューを送信して、メニューオプションの選択として番号を返すことができました。

リモートプログラムは私の応答を受信し、選択したコマンドの出力を送信します。 ipconfigとwhoamiは完全に動作しますが、cmdとftpは端末の出力を1回だけ返します。 (つまり、1つのコマンドをFTPプログラムに入力し、それをリモートプログラムに送信してから、返事がないようにすることができます)

失敗する私のコードの部分は、そのif ready[0]:最初の会話の後で2回目に準備ができることはありません。

コードの代わりにnetcatを使用してcmd端末を無期限に操作できるため、リモートプログラムが正しく機能していることを知っています。

このタイプの接続を説明できるpythonソケットリスナーを適切に実装するにはどうすればよいですか?

私の「プログラム」全体:

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)

さらに情報が必要な場合はお知らせください。助けていただければ幸いです。私はこれに非常に慣れており、学びたいと思っています。

11
Mr S

しばらくこれをいじってみると、python 2.7。

それが行うことは、クライアントがクライアントのものをリッスンして接続するときに実行されるスレッドを設定することです。

クライアントがリターンを送信すると( "\ r\n"がLinuxシステムと対話する場合は変更する必要があるかもしれませんか?)メッセージがサーバーに出力されますが、これはサーバー側にraw入力がある場合に発生します。クライアントに送信されます:

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()

上記の回答は、複数の接続に対しては機能しません。接続を取得するための別のスレッドを追加して更新しました。複数のユーザーが接続できるようになりました。

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()

クライアントは他のクライアントの発言を見ることができません。サーバーからのメッセージはすべてのクライアントに送信されます。読者の練習問題として残しておきます。

13
Noelkd

Python 3が今でもソケットについて疑問に思っている場合は、ソケットの基本的な使用方法を次に示します。

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'))
_

最初にserver.pyを実行し、次にclient.pyを実行します

これは、currentTimeを送受信するだけです。

Python 3.4 sockets?の新機能

python 2.7ソケットとpython 3.4ソケットの主な違いは、メッセージの送信です。.encode()を使用する必要があります(通常は 'ascii'またはパラメーター/引数として空白)、次に.decode()を使用

たとえば、送信には.encode()を使用し、受信には.decode()を使用します。

追加情報: クライアント/サーバーソケットのチュートリアル

6
Leigh Flix