0

こんばんは、このサイトにアクセスするのはこれが初めてです。過去3か月間、Pythonベースのユーザー監視システムをプログラミングしており、最初のリリースはほぼ完了しています。しかし、接続したいコンピューターを制御する際に問題が発生しました。

この投稿に記載した2つのサンプルコードを実行すると、サーバーでクライアントを受信して​​クライアントにコマンドを送信できますが、一度に1つのクライアントしか送信できず、サーバーが送信できるクライアントと次のクライアントを指定します。 。問題は「サーバー側」だと確信していますが、問題を解決する方法がわかりません。Google検索では、これを試した人は誰も見つかりません。

この投稿では、クライアントベースとサーバーベースの両方のネットワークコードを添付しました。

クライアント:

import asyncore
import socket
import sys
do_restart = False
class client(asyncore.dispatcher):
    def __init__(self, host, port=8000):
        serv = open("srv.conf","r")
        host = serv.read()
        serv.close()
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((host, port))
    def writable(self):
        return 0
    def handle_connect(self):
        pass           
    def handle_read(self):
        data = self.recv(4096)
        #Rest of code goes here 
serv = open("srv.conf","r")
host = serv.read()
serv.close()
request = client(host)
asyncore.loop()

サーバ:

import asyncore
import socket
import sys
class  soc(asyncore.dispatcher):
    def __init__(self, port=8000):
        asyncore.dispatcher.__init__(self)   
        self.port = port
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.bind(('', port))
        self.listen(5)
    def handle_accept(self):
        channel, addr = self.accept()
        while 1:
            j = raw_input(addr)
            #Rest of my code is here
server = soc(8000)
asyncore.loop()
4

2 に答える 2

0

私に

    while 1:
        j = raw_input(addr)

問題のようです。ソケットを受け入れるだけで、最後までそれを使って何かをします。

接続するすべてのクライアントに対して新しいディスパッチャを作成する必要があります

class  conn(asyncore.dispatcher):
     ...
     def handle_read(self):
         ...

class  soc(asyncore.dispatcher):
     def handle_accept(self):
         ...
         c = conn()
         c.set_socket(channel)

Asyncoreは、可能なすべての読み取り操作に対してコールバックします。

Asyncoreは1つのスレッドのみを使用します。これがその強みです。ソケットを持つすべてのディスパッチャは、これらの機能を使用して次々に呼び出されhandle_*ます。

于 2012-09-13T23:19:36.403 に答える
0

これが私が一緒に投げた速くて汚い考えです。

の使用はraw_input、非同期互換の別のディスパッチャに置き換えられました。ここでこの他の質問を参照してください。

そして、@ user1320237によって与えられた回答を拡張して、新しいディスパッチャへの新しい接続を延期します。

接続されている任意のクライアントに制御コマンドを送信できる単一のコマンドラインインターフェイスが必要でした。つまり、それらを切り替える方法が必要です。私が行ったことは、接続されたクライアントを追跡するためのdictを作成したことです。次に、コマンドラインのコールバックにマップする一連の使用可能なコマンドも作成します。

この例には次のものがあります。

  • list:現在のクライアントを一覧表示
  • set <client>:現在のクライアントを設定
  • send <msg>:現在のクライアントにメッセージを送信します

server.py

import asyncore
import socket
import sys
from weakref import WeakValueDictionary


class Soc(asyncore.dispatcher):

    CMDS = {
        'list': 'cmd_list',
        'set': 'cmd_set_addr',
        'send': 'cmd_send',
    }

    def __init__(self, port=8000):
        asyncore.dispatcher.__init__(self)  

        self._conns = WeakValueDictionary()
        self._current = tuple()

        self.port = port
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind(('', port))
        self.listen(5)

        self.cmdline = Cmdline(self.handle_input, sys.stdin)
        self.cmdline.prompt()


    def writable(self):
        return False

    def handle_input(self, i):
        tokens = i.strip().split(None, 1)
        cmd = tokens[0]
        arg = ""
        if len(tokens) > 1:
            arg = tokens[1]

        cbk = self.CMDS.get(cmd)
        if cbk:
            getattr(self, cbk)(arg)

        self.cmdline.prompt(self._addr_to_key(self._current))

    def handle_accept(self):
        channel, addr = self.accept()
        c = Conn(channel)
        self._conns[self._addr_to_key(addr)] = c

    def _addr_to_key(self, addr):
        return ':'.join(str(i) for i in addr)

    def cmd_list(self, *args):
        avail = '\n'.join(self._conns.iterkeys())
        print "\n%s\n" % avail

    def cmd_set_addr(self, addr_str):
        conn = self._conns.get(addr_str)
        if conn:
            self._current = conn.addr

    def cmd_send(self, msg):
        if self._current:
            addr_str = self._addr_to_key(self._current)
            conn = self._conns.get(addr_str)
            if conn:
                conn.buffer += msg         


class Cmdline(asyncore.file_dispatcher):
    def __init__(self, cbk, f):
        asyncore.file_dispatcher.__init__(self, f)
        self.cbk = cbk

    def prompt(self, msg=''):
        sys.stdout.write('%s > ' % msg)
        sys.stdout.flush()        

    def handle_read(self):
        self.cbk(self.recv(1024))


class Conn(asyncore.dispatcher):

    def __init__(self, *args, **kwargs):
        asyncore.dispatcher.__init__(self, *args, **kwargs)  
        self.buffer = ""

    def writable(self):
        return len(self.buffer) > 0

    def handle_write(self):
        self.send(self.buffer)
        self.buffer = ''

    def handle_read(self):
        data = self.recv(4096)
        print self.addr, '-', data


server = Soc(8000)
asyncore.loop()

これで、メインサーバーがブロックされることはなくstdin、常に新しい接続を受け入れます。それが行う唯一の作業は、高速操作であるか、メッセージを処理するように接続オブジェクトに信号を送るコマンド処理です。

使用法:

# start the server
# start 2 clients
> 
> list

127.0.0.1:51738
127.0.0.1:51736

> set 127.0.0.1:51736
127.0.0.1:51736 >
127.0.0.1:51736 > send foo

# client 127.0.0.1:51736 receives "foo"
于 2012-09-14T01:26:27.200 に答える