0

晚上好,这是我第一次访问这个网站,在过去的 3 个月里,我一直在为我的工作编写一个基于 python 的用户监控系统,我的第一个版本几乎完成了。但是,我在控制要连接的计算机时遇到了问题。

如果我运行我在这篇文章中放置的两个示例代码,我可以接收客户端并向服务器发送命令,但一次只能发送一个客户端,服务器决定我可以发送到哪个客户端,下一个是哪个客户端. 我确定问题出在“服务器端,但我不知道如何解决这个问题,而且谷歌搜索没有出现任何尝试过这个的人。

我在这篇文章中附加了基于客户端和服务器的网络代码。

客户:

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

这是我提出的一个快速而肮脏的想法。

的使用raw_input已被另一个异步兼容的调度程序替换,在此处引用另一个问题

我正在扩展@user1320237 给出的答案,以将每个新连接推迟到新的调度程序。

您希望拥有一个可以向任何连接的客户端发送控制命令的命令行界面。这意味着您需要一种在它们之间切换的方法。我所做的是创建一个字典来跟踪连接的客户端。然后我们还创建了一组可用的命令,这些命令映射到您的命令行的回调。

此示例具有以下内容:

  • list: 列出当前客户
  • set <client>: 设置当前客户端
  • send <msg>: 向当前客户端发送一条消息

服务器.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 回答
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 只使用一个线程。这就是它的力量。每个具有套接字的调度程序都被这些handle_*函数一个接一个地调用。

于 2012-09-13T23:19:36.403 回答