How to make a simple command-line chat in Python?

I study network programming and would like to write a simple command-line chat in Python.

I'm wondering how make receving constant along with inputing available for sending at any time.

As you see, this client can do only one job at a time:

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

So if another client sends a message, this client will only receive it after sending a message too. I bet you understand me. I have googled for the matter and found out many interesting things such as asynchronous I/O, threading, non-blocking synchronization, concurrent programming and so on. I have also installed the twisted package. In brief, I've been learning all these things but yet haven't found what I was looking for. (Of course, I will keep trying and trying until I get to the point.)

So, my question is how make that? =)


Asked by: Adelaide329 | Posted: 30-11-2021






Answer 1

Your question was not very coherent. However, your program does not need to be asynchronous at all to attain what you are asking for.

This is a working chat script you originally wanted with minimal changes. It uses 1 thread for receiving and 1 for sending, both using blocking sockets. It is far simpler than using asynchronous methods.

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

Answered by: Catherine598 | Posted: 01-01-2022



Answer 2

If you want to code it from scratch select is the way to go (and you can read on Google Book Search most of the chapter of Python in a Nutshell that covers such matters); if you want to leverage more abstraction, asyncore is usable, but Twisted is much richer and more powerful.

Answered by: Kellan506 | Posted: 01-01-2022



Answer 3

Chat programs are doing two things concurrently.

  1. Watching the local user's keyboard and sending to the remote user (via a socket of some kind)

  2. Watching the remote socket and displaying what they type on the local console.

You have several ways to do this.

  1. A program that opens socket and keyboard and uses the select module to see which one has input ready.

  2. A program that creates two threads. One threads reads the remote socket and prints. The other thread reads the keyboard and sends to the remote socket.

  3. A program that forks two subprocesses. One subprocess reads the remote socket and prints. The other subprocess reads the keyboard and sends to the remote socket.

Answered by: Ned271 | Posted: 01-01-2022



Answer 4

Well, well, here's what I am having at this very moment.

Server goes like this:

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

And client goes just like this:

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

Now it's time to make the code look better and add some functionality.

Thanks for your help, folks!

Answered by: Brianna128 | Posted: 01-01-2022



Answer 5

You should use select.

Check:

Answered by: Haris859 | Posted: 01-01-2022



Answer 6

I wrote one in async I/O... its a lot easier to wrap your head around than a full threading model.

if you can get your hands ahold of "talk"'s source code, you can learn a lot about it. see a demo http://dsl.org/cookbook/cookbook_40.html#SEC559 , or try it your self if you are on a linux box...

it sends characters in real-time.

also, ytalk is interactive and multiple users.... kinda like hudddlechat or campfire.

Answered by: Elise841 | Posted: 01-01-2022



Similar questions

linux - How to make a python, command-line program autocomplete arbitrary things NOT interpreter

I am aware of how to setup autocompletion of python objects in the python interpreter (on unix). Google shows many hits for explanations on how to do this. Unfortunately, there are so many references to that it is difficult to find what I need to do, which is slightly different. I need to know how to enable, tab/auto completion of arbitrary items in a command-line program written in ...


java - OCSP command-line test tool?

Closed. This question does not meet Stack Overflow guid...


python - How to prompt for user input and read command-line arguments

Closed. This question needs to be more focused. It ...


eclipse - Integrating command-line generated python .coverage files with PyDev

My build environment is configured to compile, run and create coverage file at the command line (using Ned Batchelder coverage.py tool). I'm using Eclipse with PyDev as my editor, but for practical reasons, it's not possible/convenient for me to convert my whole build environment to Eclipse (and thus generate the coverage data directly from the IDE, as it's designed to do) PyDev seems to be using the same ...


c++ - How do I compile a Visual Studio project from the command-line?

I'm scripting the checkout, build, distribution, test, and commit cycle for a large C++ solution that is using Monotone, CMake, Visual Studio Express 2008, and custom tests. All of the other parts seem pretty straight-forward, but I don't see how to compile the Visu...


interpreter - Persistent Python Command-Line History

I'd like to be able to "up-arrow" to commands that I input in a previous Python interpreter. I have found the readline module which offers functions like: read_history_file, write_history_file, and set_startup_hook. I'm not quite savvy enough to put this into practice though, so could someone please help? My thoughts on the solution are: (1) Modify .login PYTHO...


data structures - Processing command-line arguments in prefix notation in Python

I'm trying to parse a command-line in Python which looks like the following: $ ./command -o option1 arg1 -o option2 arg2 arg3 In other words, the command takes an unlimited number of arguments, and each argument may optionally be preceded with an -o option, which relates specifically to that argument. I think this is called a "prefix notation". In the Bourne shell I wo...


Display constantly updating information in-place in command-line window using python?

I am essentially building a timer. I have a python script that monitors for an event and then prints out the seconds that have elapsed since that event. Instead of an ugly stream of numbers printed to the command line, I would like to display only the current elapsed time "in-place"-- so that only one number is visible at any given time. Is there a simple way to do this? If possible I'd like to u...


python - How to write script output to file and command-line?

I have a long-running Python script that I run from the command-line. The script writes progress messages and results to the standard output. I want to capture everything the script write to the standard output in a file, but also see it on the command line. Alternatively, I want the output to go to the file immediately, so I can use tail to view the progress. I have tried this: python MyLongRu...


python - Linux command-line call not returning what it should from os.system?

I need to make some command line calls to linux and get the return from this, however doing it as below is just returning 0 when it should return a time value, like 00:08:19, I am testing the exact same call in regular command line and it returns the time value 00:08:19 so I am confused as to what I am doing wrong as I thought this was how to do it in python. import os...






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top