1

I'm trying to get this simple python chat server up and running: http://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server

It's working fine, except that I have to manually select a new port each time. Otherwise, I get an Error 98 saying that the port is already in use.

How to close a socket left open by a killed program? Recommended I use some SO_REUSEADDR: thing but I have no idea how to implement that into my barebones python program. Granted, I am a nub.

This page suggests doing some crazy autoselection but that sounds a bit more complicated than I need. http://twistedmatrix.com/pipermail/twisted-python/2005-August/011098.html

Thanks to anybody who can help me!

from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor


class IphoneChat(Protocol):
def connectionMade(self):
    #self.transport.write("""connected""")
    self.factory.clients.append(self)
    print "clients are ", self.factory.clients

def connectionLost(self, reason):
    self.factory.clients.remove(self)

def dataReceived(self, data):
    #print "data is ", data
    a = data.split(':')
    if len(a) > 1:
        command = a[0]
        content = a[1]

        msg = ""
        if command == "iam":
            self.name = content
            msg = self.name + " has joined"

        elif command == "msg":
            msg = self.name + ": " + content

        print msg

        for c in self.factory.clients:
            c.message(msg)

def message(self, message):
    self.transport.write(message + '\n')


factory = Factory()
factory.protocol = IphoneChat
factory.clients = []

reactor.listenTCP(80, factory)
print "Iphone Chat server started"
reactor.run()
Community
  • 1
  • 1
Joenarr Bronarsson
  • 515
  • 2
  • 5
  • 20
  • 2
    Twisted already sets `SO_REUSEADDR` for you. This means you don't have to set it yourself, and you shouldn't encounter this error (unless you're on Windows, a platform unsuitable for server deployment). Perhaps you can share a minimal example () that produces this behavior so someone can understand and explain why it happens. – Jean-Paul Calderone Aug 11 '12 at 11:12
  • Sure - from the above site. It's quite concise already. – Joenarr Bronarsson Aug 15 '12 at 22:15
  • The code works for me, as I would expect. Also, the indentation is horribly messed up, and there's lots of extraneous stuff in the example that's not related to errors bindings ports. And you didn't mention what platform you're running this on. – Jean-Paul Calderone Aug 16 '12 at 15:15

1 Answers1

0

The following codes try to set SO_REUSEPORT .

import logging
import socket
import sys

from twisted.internet import reactor, tcp
from twisted.internet.protocol import Factory, Protocol


class Echo(Protocol):
    def dataReceived(self, data):
        logging.warning('Recv %s', data)
        self.transport.write(data)


class ReusePort(tcp.Port):

    def createInternetSocket(self):
        s = tcp.Port.createInternetSocket(self)
        if not hasattr(socket, "SO_REUSEPORT"):
            logging.warning('Not support socket.SO_REUSEPORT')
            return s
        if (
            'bsd' in sys.platform or
            sys.platform.startswith('linux') or
            sys.platform.startswith('darwin')
        ):
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
            logging.warning('Successfully set socket.SO_REUSEPORT')
        else:
            logging.warning(f'Not set socket.SO_REUSEPORT on {sys.platform}')
        return s


f = Factory()
f.protocol = Echo
p = ReusePort(6666, f)
p.startListening()
reactor.run()

You can start multiple processes at the same time. They all bind to port 6666. Note: On Linux, the connections will be balanced to these processes. But on macOS, only the first process gets all the connections.

References:

lk_vc
  • 1,136
  • 20
  • 26