Как сделать простой сеанс командной строки в Python?
Я изучаю сетевое программирование и хотел бы написать простой чат командной строки в Python.
Мне интересно, как сделать приемник постоянным вместе с вводом доступных для отправки в любое время.
Как вы видите, этот клиент может выполнять только одно задание за раз:
from socket import *
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
while 1:
data = raw_input('> ')
if not data: break
tcpCliSock.send(data)
data = tcpCliSock.recv(BUFSIZE)
if not data: break
print data
tcpCliSock.close()
Поэтому, если другой клиент отправит сообщение, этот клиент получит его только после отправки сообщения. Держу пари, ты меня понимаешь. Я искал этот вопрос и узнал много интересного, такого как асинхронный ввод-вывод, потоковая передача, неблокирующая синхронизация, параллельное программирование и так далее. Я также установил скрученный пакет. Короче говоря, я все это изучал, но пока не нашел того, что искал. (Конечно, я буду продолжать пытаться и пытаться, пока не дойду до сути.)
Итак, мой вопрос - как это сделать? =)
Ответы
Ответ 1
Ваш вопрос был не очень последовательным. Тем не менее, ваша программа не обязательно должна быть асинхронной для достижения того, о чем вы просите.
Это рабочий чат script, который вы изначально хотели с минимальными изменениями. Он использует 1 поток для приема и 1 для отправки, используя блокирующие сокеты. Это намного проще, чем использование асинхронных методов.
from socket import *
from threading import Thread
import sys
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
def recv():
while True:
data = tcpCliSock.recv(BUFSIZE)
if not data: sys.exit(0)
print data
Thread(target=recv).start()
while True:
data = raw_input('> ')
if not data: break
tcpCliSock.send(data)
tcpCliSock.close()
Ответ 2
Если вы хотите закодировать его с нуля select
- это путь (и вы можете читать в книге Поиск книг Google часть главы Python в двух словах, которая охватывает такие вопросы); если вы хотите использовать больше абстракции, asyncore
можно использовать, но Twisted намного богаче и мощнее.
Ответ 3
Программы чата выполняют две вещи одновременно.
-
Просмотр локальной клавиатуры пользователя и отправка удаленному пользователю (через какой-либо сокет)
-
Просмотр удаленного сокета и отображение того, что они набирают на локальной консоли.
У вас есть несколько способов сделать это.
-
Программа, которая открывает сокет и клавиатуру, и использует модуль select, чтобы увидеть, какой из них имеет готовый вход.
-
Программа, которая создает два потока. Один поток читает удаленный сокет и печатает. Другой поток читает клавиатуру и отправляет ее в удаленный сокет.
-
Программа, которая разворачивает два подпроцесса. Один подпроцесс считывает удаленный сокет и печатает. Другой подпроцесс читает клавиатуру и отправляет ее в удаленный сокет.
Ответ 4
Хорошо, хорошо, вот что я имею в этот самый момент.
Сервер выглядит следующим образом:
import asyncore
import socket
clients = {}
class MainServerSocket(asyncore.dispatcher):
def __init__(self, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(('',port))
self.listen(5)
def handle_accept(self):
newSocket, address = self.accept( )
clients[address] = newSocket
print "Connected from", address
SecondaryServerSocket(newSocket)
class SecondaryServerSocket(asyncore.dispatcher_with_send):
def handle_read(self):
receivedData = self.recv(8192)
if receivedData:
every = clients.values()
for one in every:
one.send(receivedData+'\n')
else: self.close( )
def handle_close(self):
print "Disconnected from", self.getpeername( )
one = self.getpeername( )
del clients[one]
MainServerSocket(21567)
asyncore.loop( )
И клиент идет так:
from Tkinter import *
from socket import *
import thread
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.create_widgets()
self.socket()
def callback(self, event):
message = self.entry_field.get()
tcpCliSock.send(message)
def create_widgets(self):
self.messaging_field = Text(self, width = 110, height = 20, wrap = WORD)
self.messaging_field.grid(row = 0, column = 0, columnspan = 2, sticky = W)
self.entry_field = Entry(self, width = 92)
self.entry_field.grid(row = 1, column = 0, sticky = W)
self.entry_field.bind('<Return>', self.callback)
def add(self, data):
self.messaging_field.insert(END, data)
def socket(self):
def loop0():
while 1:
data = tcpCliSock.recv(BUFSIZE)
if data: self.add(data)
thread.start_new_thread(loop0, ())
root = Tk()
root.title("Chat client")
root.geometry("550x260")
app = Application(root)
root.mainloop()
Теперь пришло время сделать код более удобным и добавить некоторые функции.
Спасибо за помощь, ребята!
Ответ 5
Вы должны использовать select.
Check:
Ответ 6
Я написал один в async I/O... его намного легче оборачивать вокруг, чем полная модель потоковой передачи.
если вы можете получить свои руки от "говорящего" исходного кода, вы можете многому научиться об этом. см. демонстрацию http://dsl.org/cookbook/cookbook_40.html#SEC559 или попробуйте сами, если вы находитесь в окне linux...
он отправляет символы в режиме реального времени.
также, ytalk является интерактивным и несколькими пользователями... вроде как hudddlechat или campfire.