2014-12-22 3 views
1

한 번에 최대 3 개의 요청을 처리하는 서버를 실행해야합니다. 내 디자인은 TCP 서버가 실행 중이고이 요청을 처리하기 위해 3 개의 스레드가 실행 중입니다. 서버는 요청을 받아들이고 해당 요청을 해당 대기열을 사용하여 스레드에 전달합니다. 큐에 적절한 잠금 장치가 있습니다. 내 문제는 비록 메인 프로세스가 플래그를 사용하여 종료해야 할 때 스레드에게 신호를 보내도록 시그널 핸들러를 가지고있다. 나는 정상적인 종료가 예상대로 일어나지 않기 때문에 오류가 무엇인지 이해하지 못하고있다. 출력은 다음과 같습니다TCP 쓰레드 파이썬 서버가 예상대로 신호를 처리하지 않습니다.

vm:~/Desktop$ python multi_threaded_queueing.py 
About to kickoff 
About to kickoff 
Starting Thread-1 
About to kickoff 
Starting Thread-2 
Starting Thread-3 
^CTraceback (most recent call last): 
    File "multi_threaded_queueing.py", line 94, in <module> 
    conn, addr = s.accept() 
    File "/usr/lib/python2.7/socket.py", line 202, in accept 
    sock, addr = self._sock.accept() 
socket.error: [Errno 4] Interrupted system call 

코드는 다음과 같습니다 :

#!/usr/bin/python 

import Queue 
import threading 
import time 
import sys 
import socket 
import signal 


HOST = '127.0.0.1' 
PORT = 50007    # Arbitrary non-privileged port 
s = None 

exitFlag = 0 
#signal handler for control C 
def signal_handler(signal, frame): 
    print "Control+C has been pressed" 
    #setting the exit flag so that all the threads can get notified 
    exitFlag = 1 
    #wait till all the threads have finished processing and can gracefully exit 
    #I maintain an array for each thread to set the corresponding index when 
    #it has finished its processing. I and all the elements to see if its 0 
    #and based on which I will exit or wait 
    while 1: 
     num = 0 
     for ele in exitList: 
      num &= ele 
     if ele == 0: 
      sys.exit(0) 

class myThread (threading.Thread): 
    #have a queue, thread ID and name for every thread. 
    def __init__(self, threadID, name, q): 
     threading.Thread.__init__(self) 
     self.threadID = threadID 
     self.name = name 
     self.q = q 
    def run(self): 
     print "Starting " + self.name 
     process_data(self.name, self.q, self.threadID) 
     print "Exiting " + self.name 

def process_data(threadName, q, threadID): 
    #while exit flag is not set by the main thread keep processing the data 
    #present in the queue. 
    while not exitFlag: 
     queueLock[threadID].acquire() 
     if not workQueue[threadID].empty(): 
      data = q[threadID].get() 
      queueLock[threadID].release() 
      print "%s processing %s" % (threadName, data) 
     else: 
      queueLock[threadID].release() 
     time.sleep(1) 
    exitThread[threadID] = 1 

threadList = ["Thread-1", "Thread-2", "Thread-3"] 
nameList = ["One", "Two", "Three", "Four", "Five"] 
queueLock = [] 
workQueue = [] 
threads = [] 
threadID = 0 
exitList = [] 
size = 3 
request = 0 
signal.signal(signal.SIGINT, signal_handler) 

# Create new threads 
#by default hard coding the number of threads to 3 
for tName in threadList: 
    workQueue.append(Queue.Queue(10)) 
    queueLock.append(threading.Lock()) 
    exitList.append(0) 
    thread = myThread(threadID, tName, workQueue) 
    print "About to kickoff" 
    thread.start() 
    threads.append(thread) 
    threadID += 1 


for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): 
    af, socktype, proto, canonname, sa = res 
    try: 
     socket.setdefaulttimeout(10) 
     s = socket.socket(af, socktype, proto) 
    except socket.error, msg: 
     s = None 
     continue 
    try: 
     s.bind(sa) 
     s.listen(1) 
    except socket.error, msg: 
     s.close() 
     s = None 
     continue 
    break 
if s is None: 
    print 'could not open socket' 
    sys.exit(1) 
while 1: 
    conn, addr = s.accept() 
    print 'Connected by', addr 
    request += 1 
    #round robin scheduling for each thread 
    thread_index = request % size 
    while 1: 
     data = conn.recv(1024) 
     if not data: break 
     # Fill the queue with the request received 
     queueLock[thread_index].acquire() 
     for word in nameList: 
      workQueue[thread_index].put(word) 
     queueLock[thread_index].release() 
     # Wait for queue to empty 
     while not workQueue[thread_index].empty(): 
      pass 
     conn.send(data) 
    conn.close() 



# Notify threads it's time to exit 
exitFlag = 1 
print "setting the exitFlag" 
# Wait for all threads to complete 
for t in threads: 
    t.join() 
print "Exiting Main Thread" 
+0

스레드 대신 다중 처리 (프로세스)를 사용해 보셨습니까? 서로 다른 스레드에서 여러 호출을 수락 할 수는 없습니다. 다중 처리 모듈을 사용하면 별도의 실행 환경에서 세 가지 프로세스를 수행 할 수 있습니다. –

답변

1

일이 일어나고 몇 가지가 있습니다.

  1. signal_handler(signal, frame): 글로벌 exitFlag 설정되지 않습니다. 함수 상단에 global exitFlag을 추가해야합니다.

  2. sys.exit() 실제로 종료되지 않습니다. 단지 KeyboardInterrupt 오류가 발생합니다.

  3. socket.error: [Errno 4] Interrupted system call은 좋은 것들이며, 무엇이 프로그램이 계속 방해받지 않도록합니다. conn, addr = s.accept(). socket.error 예외를 잡아서 while 루프에서 벗어나기 위해 사용해야합니다.

+0

글로벌 도움말! 그 부분을 완전히 놓친 것! sys.exit() 대신 SystemExit (0)을 사용했는데 제대로 작동하는 것 같습니다. 팁 주셔서 감사. :) .. –

관련 문제