首页 > 解决方案 > 通过 Python 套接字从客户端使用对象方法

问题描述

我的目标基本上是拥有我创建的这个“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 对象中存储和检索信息。

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

服务器.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)

客户端.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”命令,因为字典基本上是在客户端脚本结束后重建的。

标签: pythonsocketsmemcached

解决方案


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

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

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

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

我不使用JSONsplitshlex.split要正确拆分set X "hello world"['set', 'X', 'hello world']

服务器.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()

客户端.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()

推荐阅读