Как сделать простой сеанс командной строки в 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()

Теперь пришло время сделать код более удобным и добавить некоторые функции.

Спасибо за помощь, ребята!

Ответ 6

Я написал один в async I/O... его намного легче оборачивать вокруг, чем полная модель потоковой передачи.

если вы можете получить свои руки от "говорящего" исходного кода, вы можете многому научиться об этом. см. демонстрацию http://dsl.org/cookbook/cookbook_40.html#SEC559 или попробуйте сами, если вы находитесь в окне linux...

он отправляет символы в режиме реального времени.

также, ytalk является интерактивным и несколькими пользователями... вроде как hudddlechat или campfire.