I have created a client server program (in python), wherein the client(CMD for e.g.) establishes a TCP connection with the server, queries for the information regarding a particular process and if the process consumes memory more than the threshold, the server kills the process and restarts it,with the client connection being terminated. I am able to create multiple clients querying for different processes, the problem arises when two or more clients query the SAME PROCESS to the server. Ideally, the process should be killed, restarted and the both the client connections be terminated. The problem is only one of the client's connection gets terminated while the other clients continue to hang on the connection and even though the process is restarted, other client continue to hang and their connection never get terminated. Is it the problem of deadlock?
My code for reference(Any changes to the code would be appreciated to handle this problem)
# A CLIENT-SERVER ARCHITECTURE TO GET INFO ABOUT RUNNING PROCESSES ON THE SYSTEM
from thread import *
import threading
import time
import psutil
import itertools
import ctypes
import string
import os
import sys
import socket
import subprocess
exitFlag = 0
#function returning the list of all the valid partitions of the system...
def drives():
drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
return list(itertools.compress(string.ascii_uppercase,map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
def proc_info(conn,addr): # prints the process's info which match the keyword....... SERVER SIDE
conn.send('Welcome to the server\n')
name=[]
c=drives()
o=[]
t=0
m=0
while(t<len(c)):
o.append(str(c[t]+':\\'))
t=t+1
k=0
#o.reverse()
conn.send("Enter the key...\n") # for authentication purposes...e.g.here the key is 1
t=conn.recv(8)
if(t!='1'): #WRONG KEY....INVALID USER
conn.send("\nInvalid key..teminating the connection.....ABORT\n")
conn.close()
else:
r=""
conn.send("\nEnter the process keyword ..Press # @ the end ") # e.g. 'Sk' for Skype
d=conn.recv(65536)
while(d!='#'):
r=r+str(d)
d=conn.recv(65536)
for p in psutil.pids(): # iterates through all the pids of the processes obtained
try:
p1=psutil.Process(p)
if(r in p1.name()):
p2=p1.get_memory_info()
t=p1.name()+' '
d=str(p)+' '
conn.send(d)# prints the pid of the process
conn.send(t),# prints the name of the process
d=str(p2[0]/(1024*1024))+' '
conn.send(d) # print memory in MB
conn.send('MB\t')
for connect in p1.connections(kind='tcp'):
d=str(connect.laddr[0])+' '
conn.send(d) # prints ip
d=str(connect.laddr[1])+' '
conn.send(d) # prints tcp ports
except psutil.AccessDenied: # won't show all the processes
pass
except psutil.NoSuchProcess:
pass
else:
continue
conn.send(" Enter the threshold...(in MB)(Press # at the end) ")
d=""
t=conn.recv(65536).decode('utf-8')
while(t!='#'):
d=d+str(t)
t=conn.recv(65536).decode('utf-8')
names=[] # LIST OF PROCESSES TO BE KILLED...
#A RECORD IS KEPT SO THAT THEY CAN BE RESTARTED......
for p in psutil.pids():
try:
p1=psutil.Process(p)
if(r in p1.name()):
if((p2[0]/(1024*1024))>=int(d)):
m=p1.name()
m=m.encode('ascii','ignore') # converting unicode object into string object
for l in o:
f=0
for root, dirs, files in os.walk(l): # walks through the entire file system of the Windows OS
#f=0
for name in files:
if name==m:
p1.kill()
conn.send(" Finally the process is killed...... ")
f=1
conn.send(str(os.path.abspath(os.path.join(root,name))))
names.append(os.path.abspath(os.path.join(root,name)))
#pst=processThread(1,os.path.abspath(os.path.join(root,name)))
#pst.start()
#subprocess.Popen(str(os.path.abspath(os.path.join(root,name))))
#if(p):
break
if(f==1):
break
if(f==1):
break
except psutil.AccessDenied:
pass
except psutil.NoSuchProcess:
pass
else:
continue
conn.send(" Now the processes will be restarted after the connection is terminated......" )
conn.close() # closes the connection...
if(names):
for l in names:
subprocess.Popen(str(l))
class processThread(threading.Thread): # Thread class for Process Launch
def __init__(self,threadID,name):
threading.Thread.__init__(self)
self.threadID=threadID
self.name=name
def run(self):
subprocess.Popen(str(self.name))
class serverThread(threading.Thread): # Thread class for Server(FOR LISTENING)
def __init__(self, threadID, name,):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
def run(self):
threadLock.acquire()
host=raw_input("Enter the hostname.....")
HOST=socket.gethostbyname(host)
PORT=60000 # specific port available
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 as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(10) # no of connections @ one time
print self.name+' now listening'
threadLock.release()
while 1:
conn, addr = s.accept() # connection gets established here..
print 'Connected with ' + addr[0] + ':' + str(addr[1])
conn.send('Thank you for connecting ')
# creates a new thread for the client services and processes the parameter and sends it back to the client
start_new_thread(proc_info,(conn,addr))
s.close()
threadLock=threading.Lock()
thread1 =serverThread(1,"Server 1")
thread1.start() # starting the server thread...
Please explain the cause of the problem and its solution(if any).
I am pretty new myself to concurrent programming, but reading the code I get the sense that the process can be killed only once and that happens only for one of the clients. So, an additional check should be introduced which closes the connection if no process linked to this connection is running.