#python-3.x #sockets #ipc #keypress #nonblocking
#python-3.x #сокеты #ipc #нажатие клавиши #неблокирующее
Вопрос:
Я довольно новичок в программировании на Python. Я пытаюсь закодировать некоторую форму симуляции с использованием сокетов. Я могу успешно подключить несколько клиентов к серверу. Однако я хотел бы, чтобы сервер принимал клиентские подключения в ожидании некоторого ввода (скажем, клавиши enter или ввода строки с консоли / терминала). Если пользователь нажимает клавишу enter или вводит эту строку, сервер должен прекратить прием клиентских подключений и отправить список подключенных клиентов всем клиентам. Я знаю, как закодировать остальную часть, но я не знаю, где обнаружить это нажатие клавиши при приеме подключений. Это то, что у меня есть на данный момент. Я пытался искать аналогичные подходы, но я не нашел ничего, что соответствовало бы моим потребностям.
Серверный файл:
import socket, sys, traceback, json, pygame, curses, time
from threading import Thread
clientList = {}
def initialize():
serverConnect()
def serverConnect():
local_hostname = socket.gethostname()
host = socket.gethostbyname(local_hostname)
port = 6666
sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
sockfd.bind((host, port))
except:
print("Bind failed. Error : " str(sys.exc_info()))
sys.exit()
sockfd.listen(3)
cid = 0
# infinite loop - do not reset for every requests
while True:
print("Awaiting client connection...")
clientSocket, address = sockfd.accept()
cid = 1
add_client_to_list(cid, address)
ip = str(address[0])
port = str(address[1])
print("Connected with " ip ":" port)
try:
Thread(target=client_thread, args=(clientSocket, ip, port, cid, address)).start()
except:
print("Thread did not start.")
traceback.print_exc()
sockfd.close()
def client_thread(clientSocket, ip, port, cid, address, BUFSIZE = 5120):
clientAddress = address
clientID = cid
print("Sending client ID " str(clientID) " to " ip ":" port)
clientSocket.sendall(str(clientID).encode("utf-8"))
threadActive = True
while threadActive:
recdData = receive_input(clientSocket, BUFSIZE)
if "--QUIT--" in recdData:
print("Client is requesting to quit")
clientSocket.close()
print("Connection " ip ":" port " closed")
threadActive = False
else:
print("nReceived: {}".format(recdData) " from %d" %clientID)
clientSocket.sendall("-".encode("utf8"))
def receive_input(clientSocket, BUFSIZE):
recdData = clientSocket.recv(BUFSIZE)
recdDataSize = sys.getsizeof(recdData)
if recdDataSize > BUFSIZE:
print("The input size is greater than expected {}".format(recdDataSize))
decodedData = recdData.decode("utf8").rstrip() # decode and strip end of line
result = process_input(decodedData)
return result
def process_input(input_str):
return str(input_str).upper()
def add_client_to_list(client_ID, client_address):
clientList[client_ID] = client_address
print(clientList)
def send_client_list(clientSocket, clientList):
jsonList = json.dumps(clientList)
clientSocket.sendall(str(jsonList).encode("utf-8"))
def keyPress(stdscr):
"""checking for keypress"""
stdscr.nodelay(True) # do not wait for input when calling getch
return stdscr.getch()
if __name__ == "__main__":
initialize()
Клиентский файл:
import socket
import sys
import json
def initialize():
sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 6666
try:
sockfd.connect((host, port))
except:
print("Connection error")
sys.exit()
# Receiving server assigned client ID
try:
myID = sockfd.recv(1024).decode("utf-8")
print("Received ID: " myID " from server.")
except:
print("Could not receive my ID from server")
sys.exit()
print("Enter 'quit' to exit and 'list' to receive client List")
message = input(" -> ")
while True:
if message == "list":
print("Receiving clientList from server...")
try:
jsonList = sockfd.recv(8192).decode("utf-8")
clientList = json.loads(jsonList)
print("Received list: %s" % clientList)
except:
print("Could not receive list from server")
sys.exit()
elif message != 'quit':
sockfd.sendall(message.encode("utf8"))
if sockfd.recv(5120).decode("utf8") == "-":
pass
message = input(" -> ")
else:
sockfd.send(b'--quit--')
break;
if __name__ == "__main__":
initialize()
Это то, что я нашел. Это небольшой скрипт, который определяет, вводит ли пользователь {a} на консоли. И если он это делает, то печатается сообщение. В противном случае он продолжает прослушивать нажатия клавиш.
import curses, time
def keyPress(stdscr):
# checking for keypress
stdscr.nodelay(True) # do not wait for input when calling getch
return stdscr.getch()
while True:
if curses.wrapper(keyPress) == 97:
print("You pressed 'a'")
else:
pass
time.sleep(0.1)
Было бы здорово, если бы вы могли указать мне, как я могу использовать эту концепцию для обнаружения нажатия клавиши на стороне сервера и прекращения приема клиентских подключений и вызова функции для отправки списка клиентов всем клиентам. Или если у вас есть какие-либо другие подходы или предложения.
Комментарии:
1. Наиболее очевидным решением было бы использовать флаг, скажем,
accepting
переменную, изначально установленную наTrue
, и изменить ее наFalse
при нажатии кнопки / обнаружении конкретной строки. В таком случае код вашего сервера мог быть заключен вwhile accepting
блок и прекратил бы выполнение, как толькоaccepting
было установлено значениеFalse
.2.Спасибо за ваш ответ! Проблема решена… Я использовал следующий фрагмент кода…
def detect_send_client_list(stdscr): stdscr.nodelay(True) return stdscr.getch()
def detect_key_press(sockfd): while curses.wrapper(detect_send_client_list) != 83: time.sleep(1)