2009-06-20 10 views
10

Studio la programmazione di rete e vorrei scrivere una semplice chat da riga di comando in Python.Come creare una semplice chat da riga di comando in Python?

Mi chiedo come rendere costante il receving insieme all'input disponibile per l'invio in qualsiasi momento.

Come si vede, questo client può fare solo un lavoro alla volta:

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() 

Quindi, se un altro client invia un messaggio, questo cliente riceverà solo dopo l'invio di un messaggio di troppo. Scommetto che mi capisci. Ho cercato su google la questione e ho scoperto molte cose interessanti come I/O asincrono, threading, sincronizzazione non bloccante, programmazione concorrente e così via. Ho anche installato il pacchetto twistato. In breve, ho imparato tutte queste cose ma non ho ancora trovato quello che stavo cercando. (Certo, continuerò a provare e provare fino al punto.)

Quindi, la mia domanda è come farlo? =)

risposta

5

Se si vuole codificarlo da zero select è la strada da percorrere (e si può leggere su Google Ricerca Libri la maggior parte del capitolo di Python in a Nutshell che tratta tali argomenti); se si desidera sfruttare più astrazione, è possibile utilizzare asyncore, ma Twisted è molto più ricco e potente.

1

ho scritto uno in async I/O ... la sua molto più facile per avvolgere la testa in giro di un modello completo di threading.

se riesci a mettere le mani sul codice sorgente di "talk", puoi imparare molto a riguardo. vedere una demo http://dsl.org/cookbook/cookbook_40.html#SEC559, o provare se si è su una Linux box ...

invia caratteri in tempo reale.

inoltre, ytalk è interattivo e più utenti .... un po 'come hudddlechat o falò.

2

I programmi di chat stanno facendo contemporaneamente due cose.

  1. Guardando tastiera dell'utente locale e l'invio all'utente remoto (tramite una presa di qualche tipo)

  2. Guardando il socket remoto e la visualizzazione di ciò che tipo sulla console locale.

Hai diversi modi per farlo.

  1. Un programma che apre presa e la tastiera e utilizza il modulo select per vedere quale ha ingresso pronto.

  2. Un programma che crea due thread.Un thread legge il socket remoto e stampa. L'altro thread legge la tastiera e invia alla presa remota.

  3. Un programma che esegue due sottoprocessi. Un sottoprocesso legge la presa remota e stampa. L'altro sottoprocesso legge la tastiera e invia alla presa remota.

+0

http://docs.python.org/library/select.html è la documentazione peggiore che abbia mai letto. Non ci sono esempi! Non ho ottenuto nulla da quella sourse ... – user122922

+0

Ok, allora ho letto dell'API select da qualche altra parte. http://linux.die.net/man/2/select. http://www.cs.utah.edu/~swalton/listings/sockets/programs/. Google funziona. –

+0

http://docs.python.org/howto/sockets.html#non-blocking-sockets –

2

Bene, bene, ecco cosa sto avendo in questo momento.

Server va in questo modo:

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() 

E cliente va proprio come questo:

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() 

Ora è il momento per rendere il codice un aspetto migliore e aggiungere alcune funzionalità.

Grazie per il vostro aiuto, gente!

+0

Oh, stavo parlando di una chat da riga di comando ma ho finito con un'app GUI. Anche se questo non rende le cose molto diverse. – user122922

8

La tua domanda non è stata molto coerente. Tuttavia, il tuo programma non ha bisogno di essere asincrono per raggiungere ciò che stai chiedendo.

Questo è uno script di chat di lavoro che si desiderava originariamente con modifiche minime. Utilizza 1 thread per la ricezione e 1 per l'invio, entrambi utilizzando socket di blocco. È molto più semplice rispetto all'utilizzo di metodi asincroni.

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() 
+0

> È molto più semplice dell'utilizzo di metodi asincroni. Ehi, amico, dove posso usare metodi asincroni nel mio client di chat? (Beh, non mi interessa il server, sono stato interessante nei client.) Il mio client di chat è uguale al tuo, tranne che tu importi il ​​modulo di threading e io importa il modulo thread. Anche se, grazie a voi! – user122922

+0

La differenza è che hai importato asyncore, quindi hai usato metodi asincroni. Inoltre hai incluso un'intera GUI non necessaria, ma a parte questo è la stessa cosa. – Unknown

+0

Il modulo asyncore è stato importato nell'app server, non nell'app client. Да и фиг с ним ... – user122922

Problemi correlati