【问题标题】:Using an objects methods from client-side through Python Sockets通过 Python 套接字从客户端使用对象方法
【发布时间】:2021-02-12 18:44:11
【问题描述】:

我的目标基本上是拥有我创建的这个 'memcached' 对象,它基本上是一个包含一组类似于 memchached 系统的命令的字典,并从客户端的角度操作它们并实际对'进行一些更改memcached 字典对象'。

首先,我决定制作一个 memcached.py 脚本,它基本上是一个 Memcached 类,包含一些真实 Memcached 系统的命令,但作为方法。

'''Class built with the intention of simulating a real Memcached system'''

class Memcached:

def __init__(self):
    self.storage = {}

"""Storage Commands"""    
def set(self, key, value):
    self.storage[key] = value
    print("STORED")

def add(self,key,value):
    if key in self.storage:
        print("ERROR")
    else:
        self.storage[key] = value
        print("STORED")

"""Retrieval Commands"""
def get(self, key):
    response = print(f'VALUE {key} \n {self.storage[key]} \n END')
    return response

这显然可以在终端上工作,所以这是我在 Memcached 系统的复杂性方面所能做到的最远距离(当我解决更大的问题时,我将添加一些其他功能/命令)

更大的问题:

我现在要做的实际上是通过 localhost 套接字发送和接收这个 memcached 对象,因此(例如)客户端可以从我创建的这个 memcached 对象中存储和检索信息。

这些基本上是我制作的脚本:

server.py

import socket
import json
import memcached

cache = memcached.Memcached()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 12345))
s.listen(1)
print('Socket is listening...')
conn, addr = s.accept()
b = b''

with conn:
    while True:
        data = conn.recv(1024)
        b += data
        if not data:
            break

d = json.loads(b.decode('utf-8'))

args = d.split(' ')

if args[0] == 'set':
    cache.set(args[1], args[2])
elif args[0] == 'add':
    cache.add(args[1], args[2])
elif args[0] == 'get':
    cache.get(args[1], args[2])
else:
    print('ERROR')    

#control print
print(d)

client.py

import socket
import json

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 12345))

class Client:

    def __init__(self):
       self.host = 'localhost'
        self.port = 12345
 
    def command(self, command, key, value):
        cmd = command  + ' ' +  key + ' ' + value
        b = json.dumps(cmd).encode('utf-8')    
        s.sendall(b)


newClient = Client()

while True:
    print('Taking memcached commands...')
    cmd = input()
    if cmd == 'quit':
        break
    else:
        cmdList = cmd.split()
        newClient.command(cmdList[0], cmdList[1], cmdList[2])

已编辑:使用允许我从客户端加入 memcached 方法的逻辑更新了脚本。但是现在我无法从同一个连接发送不同的命令。线程是必要的还是逻辑上的简单改变可以解决这个问题?例如,在我当前的状态下,我不能使用'get'命令,因为字典基本上是在客户端脚本结束后重建的。

【问题讨论】:

  • 始终将代码、数据和完整的错误消息作为文本(不是屏幕截图)放在有问题的地方(不是评论)。
  • 你指的是什么命令?对于简单的命令,您可以简单地在空格 cmd = line.split(' ') 上拆分文本并比较子字符串 if cmd[0] == "add": add(cmd[1:])
  • 也许你应该使用不同的东西 - 即RPC (Remote Procedure Call)。见:What is the current choice for doing RPC in Python?
  • 更改了格式,使其更具可读性。由于某种原因,这是一种痛苦。我的意思是命令是 mecached 类的实际方法。因此,例如,我想从客户端向服务器发送一个请求以设置(test_key,test_value),并且服务器实际上将该键和值添加到有问题的字典中。
  • 您可以发送文本"set key_name value" 和服务器可以split(" ") 获取列表args = ["set", "key_name", "value"] 并使用if args[0] == "set": set(args[1], args[2])

标签: python sockets memcached


【解决方案1】:

您必须在while True: 中运行代码才能重复执行下一个命令。

如果你想多次连接,那么你必须在另一个while True中运行它。

我没有memcache,所以我用setaddget 创建了自己的类来模拟它。

我使用'\n' 来识别命令结束。

我不使用JSONsplit,而是使用shlex.splitset X "hello world" 正确拆分为['set', 'X', 'hello world']

server.py

import socket
import shlex
#import memcached

# --- classes ---

class MyMemcached():

    def __init__(self):

        self.data = dict()
        
    def set(self, key, val):
        print('[MyClass]: set', key, val)
        self.data[key] = val

    def add(self, key, val):
        print('[MyClass]: add', key, val)
        if key not in self.data:
           self.data[key] = ""
        self.data[key] += val
    
    def get(self, key):
        val = self.data.get(key)
        print('[MyClass]: get', key, val)
        return val

# --- main ---

#cache = memcached.Memcached()
cache = MyMemcached()

s = socket.socket()  # default values are `socket.AF_INET, socket.SOCK_STREAM`

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # solution for: `OSError: [Errno 98] Address already in use` when socket already closed

print('Bind: 0.0.0.0:12345')
s.bind(('0.0.0.0', 12345))

print('Listen: 1')
s.listen(1)  # how many clients can wait for connection

try:
    while True:  # repeat for next connection
        print('Waiting for client...')
        conn, addr = s.accept()

        print('Connected:', addr)#, conn)

        with conn:
            while True: # repeat for next command

                cmd = b''
                
                # get one command
                while True:
                    data = conn.recv(1)  # read single char until you get `\n'
                    # read until `\n'`
                    if not data or data == b'\n':
                        break

                    cmd += data
                     
                cmd = cmd.decode('utf-8')   
                
                #control print
                print('cmd:', cmd)
                        
                if cmd.lower() == 'quit':
                    break
                                           
                #args = cmd.split(' ') # it split INCORRECTLY `set a "hello world"`
                args = shlex.split(cmd)  # it split correctly `set a "hello world"`
                print('args:', args)

                if args[0] == 'set':
                    cache.set(args[1], args[2])
                elif args[0] == 'add':
                    cache.add(args[1], args[2])
                elif args[0] == 'get':
                    val = cache.get(args[1])
                    print(val)
                else:
                    print('ERROR: cmd:', cmd) 
                    break
except KeyboardInterrupt:
    print('Pressed Ctrl+C')            
finally:            
    s.close()

client.py

import socket

# --- classes ---

class Client:

    def __init__(self, host='0.0.0.0', port=8000):
        self.host = host
        self.port = port
        self.socket = socket.socket()  # default values are `socket.AF_INET, socket.SOCK_STREAM`
        self.socket.connect((self.host, self.port))
 
    def command(self, cmd):
        print('send:', cmd)
        cmd = cmd.encode('utf-8') + b'\n'    
        self.socket.sendall(cmd)

    def run(self):
        while True:
            cmd = input('cmd: ')
            self.command(cmd)

            if cmd.lower() == 'quit':
                break
    
# --- functions ---

# ... empty ...

# --- main ---

#client = Client('localhost', 12345)
client = Client(port=12345)
client.run()

【讨论】:

  • 优秀的弗拉斯。非常感谢您花时间和奉献精神帮助我解决这个问题,非常感谢。干杯伙伴。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-17
  • 1970-01-01
  • 2012-12-01
  • 2018-09-08
  • 2013-12-15
  • 2013-10-24
  • 1970-01-01
相关资源
最近更新 更多