简体   繁体   中英

How do I close a server socket while it is waiting for a connection?

I have a server program that can maintain connection with multiple clients. I want to be able to close the main server socket ( for EVERYONE) in response to the message CLOSE by client, or for some other reason. The problem is that the server is stuck on the accept() method and does not care if I close the socket in some other place.

I can use some flag in the main server while, and close the socket after this while, however that means I will have to connect to the server myself after the client request, in order for the while condition to be checked, which smells like really terrible programming.

The code:

import socket
import sys
from thread import *

HOST = ''   # Symbolic name meaning all available interfaces
PORT = 9992 # Arbitrary non-privileged port


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'

#Bind socket to local host and port
try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

print 'Socket bind complete'

#Start listening on socket
s.listen(10)
print 'Socket now listening'

#Function for handling connections. This will be used to create threads
def clientthread(conn):
    #Sending message to connected client
    conn.send('Welcome to the server. Type something and hit enter\r\n') #send only takes string
    data=''
    #infinite loop so that function do not terminate and thread do not end.
    while True:

        #Receiving from client
        data += conn.recv(1024)
        print data
        if data == 'CLOSE':
            global s
            conn.sendall('You have requested to destroy the connection...')
            conn.close()
            s.close()
            return
        if data.find('\n') != -1:
            conn.sendall('OK...' + data + '\r\n')
            data=''






#now keep talking with the client
while 1:
    #wait to accept a connection - blocking call 
    try:
        conn, addr = s.accept()
        print 'Connected with ' + addr[0] + ':' + str(addr[1])

        #start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
        start_new_thread(clientthread ,(conn,))
    except:
        print 'socket issue sorry'
        break

This is where the Python standard library lends you a helping hand. Check out the asyncore module, or Twisted .

There is usually no reason not to go asynchronous with Python, since it is so easy. As a bonus, your code will be more readable and maintainable.

Your code with asyncore :

import asyncore
import socket
import sys

HOST = ''   # Symbolic name meaning all available interfaces
PORT = 9992 # Arbitrary non-privileged port

class ExampleHandler(asyncore.dispatcher_with_send):
    data = ''

    def handle_read(self):
        self.data += self.recv(1024)
        lines = self.data.split('\n')
        if len(lines) > 1:
            self.data = lines[-1]
            for line in lines:
                if not line: continue
                if line == 'CLOSE':
                    global s
                    self.send('You have requested to destroy the connection...\r\n')
                    self.close()
                    # To exit asyncore.loop() immediately,
                    # closing all client connections
                    raise asyncore.ExitNow()
                    # If you want to finish processing the client connections, you
                    # could instead close the server, 
                    server.close()
                else:
                    self.send('OK...%s\r\n' % line)

    def handle_write(self):
        self.send('Welcome to the server. Type something and hit enter\r\n')

class ExampleServer(asyncore.dispatcher):

    def __init__(self, host, port):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind((host, port))
        self.listen(5)

    def handle_accept(self):
        pair = self.accept()
        if pair is not None:
            sock, addr = pair
            print 'Connected with ' + addr[0] + ':' + str(addr[1])
            handler = ExampleHandler(sock)
        else:
            print 'socket issue sorry'

server = ExampleServer(HOST, PORT)
try:
    asyncore.loop()
except asyncore.ExitNow:
    pass

Note: I also fixed the string/buffering problem in your original code by adding a line buffer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM