Hi,
I've been trying to code a simple file sharing system in python by using Discovery server -indexer- model
Server:
#!bin/python
import socket
import sys
import os
import threading
from utils import serialize, deserialize, PeerInfo
class NotSupportedCommand(Exception):
pass
class DiscoveryServer(object):
'''Indexer...'''
def __init__(self, port, maxPeers=5):
self.port=port
addr=('', self.port)
self.maxPeers=maxPeers
self.supportedCommands=["/register", "/setNick", "/setSharedFiles", "/showall", "/query"]
self.listener=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.listener.bind(addr)
self.tListening=threading.Thread(target=self.listeningHandler, args=[])
self.tListening.start()
self.alSocks=[]
# {clientAddr:peerInfo Object}
self.db={}
self.log=[]
self.BUF=4096
def listeningHandler(self):
self.listener.listen(self.maxPeers)
print "Server Started..."
while True:
clientSocket, clientAddr=self.listener.accept()
print "Gotta a connection from", clientAddr
tClientHandling=threading.Thread(target=self.clientHandler, args=[clientSocket])
tClientHandling.start()
clientSocket.close()
def clientHandler(self, clientSocket):
self.alSocks += [clientSocket]
formatedAddress=clientSocket.getpeername()[0]+":"+str(clientSocket.getpeername()[1])
objString=""
try:
while True:
objString=clientSocket.recv(self.BUF)
if not objString:
break
data=deserialize(objString)
#print data
tAnalyzeData=threading.Thread(target=self.analyzeData, args=[data, clientSocket])
tAnalyzeData.start()
objString=""
except Exception, e:
print "E: ", e
print clientSocket.getpeername(), " closed.."
self.alSocks.remove(clientSocket)
del self.db[formatedAddress]
def analyzeData(self, data, clientSocket):
formatedAddress=clientSocket.getpeername()[0]+":"+str(clientSocket.getpeername()[1])
try:
if isinstance(data, tuple): #registering...
pInfo=PeerInfo(data[1], data[2], data[3]) #(register, alias, files, port)
print "Registering: ", pInfo.alias
print pInfo
self.db[formatedAddress]=pInfo #peerInfo object..
print self.db
if isinstance(data, list):
try:
#split the sender's alias..
#recvd=['tina: /showall']
recvd=data[0].split(": ")[1]
cmd=recvd.split(" ")[0]
# test cmd...
if not cmd in self.supportedCommands:
self.sendToAll(data, clientSocket)
else:
if cmd=="/showall":
self.showAllTo(clientSocket)
if cmd=="/query":
fileName=recvd.split(" ")[1]
self.queryFile(fileName, clientSocket)
if cmd=="/setNick":
self.setNick(formatedAddress, recvd.split(" ")[1])
except Exception,e :
print "Error: ", e
except Exception, e:
print "Data: ", data
print "Error: ", e
self.alSocks.remove(clientSocket)
def queryFile(self, fileName, clientSocket):
print "Querying: ", fileName
data=""
for addr, pInfo in self.db.items():
if fileName in pInfo.sharedFiles:
data += "\n"+addr + " | " + pInfo.alias + " => " + fileName
data += "\n\t" + pInfo.alias + " Listens at: "+ str(pInfo.listeningPort)
print data
clientSocket.send(serialize(data))
def showAllTo(self, clientSocket):
data="\n---------------------------------------\nOnline Users:\n"
for addr, pInfo in self.db.items():
data += pInfo.alias + " -> " +addr +"\n"
data +="\n----------------------------------------\n"
print data
clientSocket.send(serialize(data))
def sendToAll(self, msg, clientEx):
print "Message Recieved: ", msg
try:
for sock in self.alSocks:
if not sock==clientEx:
sock.send(serialize(msg))
else:
pass
except Exception, e:
print "Error: ", e
def setNick(self, to, newNick):
self.db[to].alias=newNick
print "Nick Changed..."
print self.db[to]
if __name__=="__main__":
discoveryServer=DiscoveryServer(8080)
Peer
#!bin/python
import socket
import sys
import os
import threading
from utils import serialize, deserialize, PeerInfo
import random as rnd
class Peer(object):
def __init__(self, alias, serverAddr=(), sharedFiles=[]):
self.alias=alias
self.serverAddr=serverAddr
self.sharedFiles=sharedFiles
self.tcpClient=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.tcpClient.connect(self.serverAddr)
self.BUF=2048
self.listeningPort=rnd.randint(8081, 10000)
self.pInfo=PeerInfo(self.alias, self.sharedFiles, self.listeningPort)
self.addr=('', self.listeningPort)
print "\nConnected to server..."
self.tClientToServer=threading.Thread(target=self.clientToServerHandler, args=[])
self.tClientToServer.start()
#listen for connections in background..
self.listener=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.listener.bind(self.addr)
self.tListening=threading.Thread(target=self.listeningHandler, args=[])
self.tListening.start()
def registerAtServer(self):
msg=("/register", self.alias, self.sharedFiles, self.listeningPort)
self.tcpClient.send(serialize(msg))
def clientToServerHandler(self):
print "Start Chatting.."
#first register the files...
self.registerAtServer()
while True:
tServerToClient=threading.Thread(target=self.serverToClientHandler, args=[])
tServerToClient.start()
data=raw_input()
if not data:
break
if data.split(" ")[0]=="/fetch":
addr, fileneeded=data.split(" ")[1:]
tFetchFile=threading.Thread(target=self.fetchFile, args=[addr, fileneeded])
tFetchFile.start()
else:
msg=self.alias+": "+data
self.tcpClient.send(serialize([msg]))
def serverToClientHandler(self):
while True:
data=deserialize(self.tcpClient.recv(self.BUF))
if not data: break
if isinstance(data, list): #data ['tina: hi']
print data[0]
else:
print data
def fetchFile(self, addr, fileneeded):
#addr is formated => addr:listeningPort
endPoint=addr.split(":")[0], int(addr.split(":")[1])
fetchTCPClient=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
fetchTCPClient.connect(endPoint)
fetchTCPClient.send(serialize("/fetch", fileneeded, _from))
tDownloadFile=threading.Thread(target=self.downloadFile, args=[fetchTCPClient, fileneeded])
tDownloadFile.start()
def downloadFile(self, fetchTCPClient, fileneeded):
f=file(fileneeded, "wb")
while True:
dataRcvd=deserialize(fetchTCPClient.recv(self.BUF))
if not dataRcvd: break
f.write(dataRcvd)
def listeningHandler(self):
self.listener.listen(5)
while True:
clientSocket, clientAddr=self.listener.accept()
tClientHandling=threading.Thread(target=self.clientHandler, args=[clientSocket])
tClientHandling.start()
def clientHandler(self, clientSocket):
rcvd=clientSocket.recv(self.BUF)
data=deserialize(rcvd)
if isinstance(data, tuple):
if data[0]=="/fetch": #go on..
fileneeded=data[1] #(/fetch, fileneeded, _from)
f=file(fileneeded, "rb")
while True:
try:
clientSocket.send(serialize(f.read(self.BUF)))
except:
break
if __name__=="__main__":
alias=raw_input("Alias: ")
sharedFiles=os.listdir(os.getcwd())
peer=Peer(alias, ('localhost', 8080), sharedFiles)
Utils module
import marshal
class PeerInfo(object):
def __init__(self, alias, sharedFiles, listeningPort):
self.alias=alias
self.sharedFiles=sharedFiles
self.listeningPort=listeningPort
def __str__(self):
sb="Alias: " + self.alias
sb += "\nFiles: " + str(self.sharedFiles)
sb +="\nListens At:" + str(self.listeningPort)
return sb
def serialize(obj):
'''Serialize an object to a string...'''
return marshal.dumps(obj)
def deserialize(objString):
'''Deserialize an object string...'''
return marshal.loads(objString)
if __name__=="__main__":
p=PeerInfo("tina", [1, 2, 3 ,4], 80)
print p
print "alias: ",p.alias
print "files: ", p.sharedFiles
print "port : ", p.listeningPort
And it works (Querying, chating, changing nickS)
the only problem is when i try tofetch a file; it raises connection refused exception
any ideas ?