1

I've been following the tutorials and now have a twisted reactor running. I've used telnet to test that it does stuff but I've not managed to find anything in the twisted tutorials on how to connect to the reactor.

My assumption was there would be something within twisted to do this, should I instead use the built in socket?

Edit:

This is the Server script:

import time
import multiprocessing

from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor

class TTT(LineReceiver):
    def __init__(self, users):
        self.users = users
        self.name = None
        self.state = "GETNAME"

    def connectionMade(self):
        self.sendLine("You are connected")

    def connectionLost(self, reason):
        if self.users.has_key(self.name):
            del self.users[self.name]

    def lineReceived(self, line):
        if line == "quit":
            reactor.stop()

        if self.state == "GETNAME":
            self.handle_GETNAME(line)
        else:
            self.handle_CHAT(line)

    def handle_GETNAME(self, name):
        if self.users.has_key(name):
            self.sendLine("Name taken, please choose another.")
            return
        self.sendLine("Welcome, %s!" % (name,))
        self.name = name
        self.users[name] = self
        self.state = "CHAT"

    def handle_CHAT(self, message):
        message = "<%s> %s" % (self.name, message)
        for name, protocol in self.users.iteritems():
            if protocol != self:
                protocol.sendLine(message)


class TTTFactory(Factory):
    def __init__(self):
        self.state = [0 for x in range(9)]
        self.turn = -1

        self.users = {} # maps user names to Chat instances

    def make_move(self, player, x, y):
        if player != self.turn:
            return "Not your turn"

        i = x + y * 3

        if self.state[i] != 0:
            return "Invalid move"

        self.state[i] = player

        # Horrizontal
        if self.state[0] == self.state[1] == self.state[2]: return "Win"
        if self.state[3] == self.state[4] == self.state[5]: return "Win"
        if self.state[6] == self.state[7] == self.state[8]: return "Win"

        # Vertical
        if self.state[0] == self.state[3] == self.state[6]: return "Win"
        if self.state[1] == self.state[4] == self.state[7]: return "Win"
        if self.state[2] == self.state[5] == self.state[8]: return "Win"

        # Diagonal
        if self.state[0] == self.state[4] == self.state[8]: return "Win"
        if self.state[6] == self.state[4] == self.state[2]: return "Win"

        # Swap turn
        self.turn = 0 - self.turn
        return "Next move"

    def buildProtocol(self, addr):
        return TTT(self.users)

# def reactor_runner():
def new_server(conn):
    port_num = 8007
    conn.send(port_num)

    reactor.listenTCP(port_num, TTTFactory())
    reactor.run()

I want to have another python program/process send and recieve messages from it. The idea behind the project is create a multiplayer tic tac toe game.

I want to have a server process and 1 or more client processes. For ease of running I'm currently using multiprocessing to run them at the same time. When complete the client process needs to be able to connect over a network as it may not be on the same computer as the host.

nosklo
  • 217,122
  • 57
  • 293
  • 297
Teifion
  • 108,121
  • 75
  • 161
  • 195
  • What do you mean with "connect to the reactor"? – ypercubeᵀᴹ Dec 04 '11 at 22:30
  • what are you trying to connect to a reactor? Can you show us what you have, and then describe what you want to do next? – SingleNegationElimination Dec 04 '11 at 22:38
  • https://github.com/Teifion/mp_tictactoe/blob/master/ttt_server.py - that's the server that runs. I want to have another program be able to send and receive messages from it. The overall project is meant to be a tic tac toe game (afterwards I plan to move on to an RTS). – Teifion Dec 04 '11 at 22:46
  • 2
    Looking at your code, you may be mistaken about how the reactor works. It is a singleton object accessible from multiple threads. There is not one reactor per server or anything like that. Your application should call reactor.run() once and any calls to methods like reactor.listenTCP() after that point will take effect immediately. – David K. Hess Dec 04 '11 at 22:50
  • I understand that part, I'm trying to have it so that separate processes (or programs across a network) can access the same reactor. The only reason it's all within one program is the host runs both a client and server application (like I said I'm new, if you've better ideas I'm genuinely interested). – Teifion Dec 04 '11 at 22:53
  • Are you trying to run twisted under multiprocessing? Better to get your twisted part running without multiprocessing first – number5 Dec 04 '11 at 22:54
  • At the moment yes but when I add a 2nd player there should be a different process completely (different computer even) connecting. I planned to write it so the client and server are kept separate. – Teifion Dec 04 '11 at 22:56
  • 2
    Multiprocessing will only confuse things as it will imply to you that you have a shared reactor when you really don't. It will be two different reactors with two different states in two different processes. I believe you would be best off moving to a completely separate client application from the beginning. – David K. Hess Dec 04 '11 at 23:05
  • @Teifion: You say *"I'm trying to have it so that separate processes (or programs across a network) can access the same reactor."* Even with your server program now, you can have many programs connecting to to your server (try with telnet, open 2 or more telnet programs and connect). – ypercubeᵀᴹ Dec 04 '11 at 23:12
  • @DavidK.Hess: I'm not trying to have more than one reactor, shared or otherwise. I'm trying to get a python program to send and receive messages with an existing reactor. The question is, does twisted have something like this already or should I be using sockets? – Teifion Dec 04 '11 at 23:20
  • @ypercube: Yes, I'm aware that I can have several (I've already had 2 telnets doing it). What I am trying to do is to have a Python program take the place of telnet in sending information. Not to mimik telnet but to be a client as part of a multiplayer game. – Teifion Dec 04 '11 at 23:20
  • So, you need a Server.py and a Client.py (either of them will have one reactor running, but doing different things). The Server will be accepting connections from many clients, the Client will be connecting to a (remote) Server. The Server will be keeping a list of connected clients (users, names, moves made, etc.) – ypercubeᵀᴹ Dec 04 '11 at 23:23
  • @ypercube A reactor takes over it's entire thread, how should I go about having a program respond to user input and update graphics if it has a reactor? – Teifion Dec 04 '11 at 23:26
  • Then your question really is "How to combine in a program a user interface (that uses X-?) and a client (that uses Twisted)" – ypercubeᵀᴹ Dec 04 '11 at 23:45
  • 2
    @Teifion, so it sounds like you need to go and look at the examples for ClientFactory. That's how you use Twisted to write a client application that can connect to your Factory. As to your threading question, there are some third party reactors (such as https://github.com/ghtdak/qtreactor) available that allow GUI toolkits such as Qt to run side-by-side with a Twisted reactor. – David K. Hess Dec 04 '11 at 23:47
  • @ypercube I wasn't sure what twisted could do with regards to that so asked the more specific question of how to achieve the above. Your suggested question in hindsight would have been the better one though. – Teifion Dec 04 '11 at 23:52

1 Answers1

3

Here's a small example of a client capable of connecting to your server above.

from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor

class TTTClientProtocol(LineReceiver):
    def lineReceived(self, line):
        line = line.strip()
        if line == 'You are connected':
            self.sendLine(self.factory.username)
        else:
            print 'SERVER SAYS:', line

class TTTClientFactory(ClientFactory):
    protocol = TTTClientProtocol 

    def __init__(self, name):
        self.username = name


name = raw_input('Please enter your name: ')
print 'Connecting...'

reactor.connectTCP('localhost', 8007, TTTClientFactory(name))

reactor.run()

I kept it as simple as I could so you could understand it easily, but to implement the chat part I would need code to read from stdin without blocking the reactor. Since you mentioned you're using a GUI instead of terminal standard input/output, then that is a lot easier actually - just choose a reactor compatible with your GUI library and then use your normal GUI events.

Hope that helps...

nosklo
  • 217,122
  • 57
  • 293
  • 297
  • 1
    If you did need to read from `stdin`, there's an API for that too: http://twistedmatrix.com/documents/current/api/twisted.internet.stdio.html – Glyph Jan 05 '12 at 20:51