Zac
Zac

Reputation: 2279

Run a python socket server and if closed remotely start it listening again

I am struggling to get my python socket to behave.

There are two major problems:

1) When it listens for the client connection the program stalls which is a problem because it is running on a IRC client python interpreter causing the IRC client not to respond until the client connects.

2) When the client disconnects the entire script has to be stopped and then restarted again inorder to get the socket server to listen once more.

I thought the way around it might be to start the socket listening in a separate thread, so the IRC client can continue while it waits for the client connection. Also, once the client has decided to close the connection I need a way restart it.

The following code is terrible and doesn't work but it might give you an idea as to what I'm attempting:

__module_name__ = "Forward Module"
__module_version__ = "1.0.0"
__module_description__ = "Forward To Flash Module by Xcom"


# Echo client program
import socket
import sys
import xchat
import thread
import time

HOST = None               # Symbolic name meaning all available interfaces
PORT = 7001              # Arbitrary non-privileged port
s = None
socketIsOpen = False

def openSocket():
    # start server
    print "starting to listen"

    for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC,
                                  socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
        af, socktype, proto, canonname, sa = res
        try:
            s = socket.socket(af, socktype, proto)
        except socket.error as msg:
            s = None
            continue
        try:
            s.bind(sa)
            s.listen(1)
        except socket.error as msg:
            s.close()
            s = None
            continue
        break
    if s is None:
        print 'could not open socket'
        global socketIsOpen = False
        sys.exit(1)
    conn, addr = s.accept()
    print 'Connected by', addr  
    global socketIsOpen = True

def someone_said(word, word_eol, userdata):
    username = str(word[0])
    message = str(word[1])
    sendMessage = username + " : " + message
    send_to_server(sendMessage)



def send_to_server(message):
    conn.send(message)


def close_connection():
    conn.close()
    print "connection closed"


xchat.hook_print('Channel Message' , someone_said)

def threadMethod(arg) :
    while 1:
        if (not socketIsOpen) :
            openSocket()

try: 
    thread.start_new_thread(threadMethod, args = [])
except:
    print "Error: unable to start thread"

The python is running on an IRC client called HexChat which is where the xchat import comes from.

Upvotes: 2

Views: 2166

Answers (1)

mata
mata

Reputation: 69032

The way you usually program a threaded socket server is:

  • call accept() in a loop
  • spawn a new thread to handle the new connection

A very minimal example would be somethig like this:

import socket
import threading
import time

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 9999))
server.listen(1)

def handle(conn):
    conn.send(b'hello')
    time.sleep(1)  # do some "heavy" work
    conn.close()

while True:
    print('listening...')
    conn, addr = server.accept()
    print('handling connection from %s' % (addr,))
    threading.Thread(target=handle, args=(conn,)).start()

You're spawning new threads in which you create your listening socket, then accept and handle your connection. And while socketIsOpen is True your programm will be using a lot of cpu looping through your while loop doing nothing. (btw, the way you check socketIsOpen allows for race conditions, you can start multiple threads before it is set.)

And one last thing, you should try to use the threading module instead of the deprecated thread.

Upvotes: 1

Related Questions