الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

P2p Exposed 1

بدأه ahmed_youssef في 20 مايو 2008 · 3 رد · 1,810 مشاهدة · في لغة Python
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

P2P Exposed

هنتكلم النهاردة بصورة مبسطة جدا عن ال Peer to Peer او Peer 2 Peer او PtP او P2P مش هتفرق يعنى! :D

المهم فى شبكات ال P2P بتكون الأجهزة مترابطة مع بعض بصورة معقدة شوية كالتالى مثلا

1_2.JPG

وبصراحة ال Model دا دراسته شيقة جدا بس للأسف هنتكلم عن ال Model دا المرة دى :D

netpeersfig04.gif

Server-Based Network وهو بيعتمد إن يكون فى Server يعمل بدور وسيط بين الأجهزة وبنطلق عليه Discovery Server او Indexer لأنه بيكون على Database بتتخزن فيها معلومات كل Peer من حيث ال Shared Files و ال Alias و .. إلخ

ملحوظة: الModel الثانى مش يعتبر P2P بصورة كاملة

اولا هنعمل Module بسيطة نعمل بيها Encapsulation للحاجات دى

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("ahmed", [1, 2, 3 ,4], 80)
	 print p
	 print "alias: ",p.alias
	 print "files: ", p.sharedFiles
	 print "port : ", p.listeningPort

ال peerInfo class هو class هنخزن فيه بيانات المستخدم عشان تكون اسهل فى التعامل والإستعلام وهى ال alias, sharedFiles, ListeningPort

هنعمل 2 methods بسيطين جدا لهندلة ال Objects اللى هتتبعت على السوكيت

وهما serialize و deserialize

بصورة مبدأية لما نفكر فى الDiscovery Server لازم يكون فيه شوية مميزات

1- ان يتم تسجيل بيانات اى حد يعمل Connect والبيانات دى بتشمل Alias, SharedFiles, ListeningPort

2- نقدر نستعلم عن الملفات الموجودة على ال Clients الآخرين

3- كل Client يقدر يعدل على بياناته

4- يقدر يعرض كل الClients الآخرين

5- يقدر يعدل على ال SharedFiles

6- اقصى عدد يقدر يتصل بالسرفر

7- وطبعا لازم يقدر يتعامل مع اكتر من Client فى نفس الوقت

8- ...................

وهكذا

ملحوظة: ممكن تعمل Clients ليهم صلاحيات اعلى "مثلا اللى مشترين pro للمنتج بتاعك"

اولا إحنا مش هنعمل DB لأننا مش منتج كبير .. احنا يدوب بنعرض الفكرة .. فال DB بتاعتنا هتكون عبارة عن Dictionary او HashTable او غيرهم حسب اللغة اللى إنت جاى منها :D

{'clientIP:port' : peerInfo Object}

اولا هنعمل socket object ونعمل set لل options بتاعته "اهم شئ REUSEADDR وهى بتسمحلك بإستخدام ال port مرة اخرى مباشرة فى حال إنك قفلت السرفر لسبب ما "وغالبا هنا الإختبار للبرنامج"

ملحوظة : مع إننا هندعم ال Chat بين المستخدمين ولكننا هنستخدم TCP مش UDP -لأننا هنتعامل مع نقل لملفات-

		 self.listener=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		 self.listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

ال Class هيبدأ بالصورة دى .. وهنحدد فيه ال port اللى هيشتغل عليه السرفر .. واقصى عدد للمستخدمين والأوامر المدعمة

/register : لتسجيل ال client

/setSharedFiles : لتعديل ال ملفات اللى معمولها share

/setNick : لتغيير ال Nick او ال alias

/showall : لعرض جميع المستخدمين

/query : للإستعلام عن ملف ما

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=2048

لاحظ مش هسجل log فى البرنامج .. هسيبهالك واجب او فرصة إنك تعدل شئ لشئ احسن وهكذا .. بحيث إنك تبقة مشارك

self.alSocks هى List هنضيف فيها كل ال Sockets المفتوحة "هتعرف بعد شوية"

لاحظ فى السطر دا

self.tListening=threading.Thread(target=self.listeningHandler, args=[])

إننا انشأنا thread للميثود listeningHandler وال args اللى هنباصيها [] List فاضية

لأنها مش بتاخد args

ولبدأ ال thread بنستخدم start method

self.tListening.start()

ال implementation الخاص بال method دى

	 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()

بنخلى السرفر يبدأ فى عملية ال listening

وبعد كدا بنعمل forever loop بنتعامل فيها مع اى client بيعمل connect وبمجرد مايعمل Connect نهندله فى thread جديد بإستخدام method بإسم clientHandler

		   tClientHandling=threading.Thread(target=self.clientHandler, args=[clientSocket])

ملحوظة accept method بتدى return ب tuple مكونة من ال clientSocket, clientAddress

 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]

ال method دى خاصة بالتعامل مع ال Client وكل اللى بتعمله فى الحقيقة هى إنها بتضيف ال ClientSocket إلى ال alSocks list اللى بال server class وتبدأ thread جديد تحلل فيه الداتا الجاية من ال Client

وطالما هتحلل data وفى thread جديد يبقة لازم نعمل method تبقة مسؤلة عن عملية ال تحليل او ال parsing لل داتا واكيد ال method دى هتاخد argument وهى ال data واللى ارسل الداتا وهو ال clientSocket

   tAnalyzeData=threading.Thread(target=self.analyzeData, args=[data, clientSocket])
				  tAnalyzeData.start()

جميل جدا .. تحليل الداتا فى الanalyzeData method

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)

انا اتبعت تكنيك بسيط شوية هنا وهو إنى بعت تسجيل البيانات على صورة tuple مكونة من

("/register", files=[], listeningPort)

وحولتها ل peerInfo object

وبعد كدا شوية إختبارات لل command نفسه لو كان query نعمل كذا لو كان كذا نعمل كذا وإذا مش كان موجود فى الأوامر المدعمة بال Server تبقة مجرد رسالة تتبعت لكل الأهل والأحباب :D

فى حال إن حصل اى ايرور يتم حذف ال Client من ال alSocks لنعرف إنه غير active او متصل بالسرفر حاليا

طب فى حال لو إن الداتا اللى إتبعتت مجرد مسج عادية ؟ يعنى هنحتاج نبعتها لكل المستخدمين ماعدا بالطبع اللى ارسلها مش كدا ؟

نجيب كل المستخدمين منين ؟

اها تمام من ال alSocks اللى بتعبر عن كل ال Clients المتفاعلين مع السرفر حاليا

قشطة

 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

جميل جدا.. فى حال لو المستخدم عايز يستعرض المتسخدمين الموجودين "اكيد رد السرفر هيكون ليه لوحده مش كدا ؟"super

فهتكون ال showallTo method كالتالى

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))

ملحوظة انا فضلت اعمل serialize لكل الداتا اللى هتتبعت حتى لو strings عشان مش اقعد اتعب نفسى فى ال de-bugging واعملهم de-serialize فى الطرف التانى

لهندلة امر تغيير ال Nick وهو /setNick

	def setNick(self, to, newNick):
		 self.db[to].alias=newNick
		 print "Nick Changed..."
		 print self.db[to]

جميل جدا ناقص ال Querying files

اللى هيطلب الإستعلام هو واحد مش كل الناس فلازم نباصى ال socket بتاعه فى ال method + نبعتله ال داتا

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))

كدا انهينا الDiscovery Server او ال Indexer

super

ننقل على ال Client او ال Peer

ال Peer لازم يتفاعل مع ال Server و يقدر يحمل ملفات من ال Peers التانين و ان يكون فى peers يقدرو يحملو منهم بردو فكدا هنعمل client ليتعامل مع السرفر ونعمل internal server يكون مسئول عن عملية ال دونلود او ال fetching

ال Constructor بتاعه هياخد

1- alias

2- list of sharedFiles

3- ال endPoint الخاصة بالسرفر

ال endPoint هى ال Server IP + port

بمجرد مايتم الconnection مع ال server نهندله فى thread جديد

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=1024
		 self.listeningPort=rnd.randint(8081, 10000)
		 self.pInfo=PeerInfo(self.alias, self.sharedFiles, self.listeningPort) 


		 print "\nConnected to server..."
		 self.tClientToServer=threading.Thread(target=self.clientToServerHandler, args=[])
		 self.tClientToServer.start()

رائع جدا

بس بردو لازم نجهز لل Peers اللى هيحاولو يعملو fetch ل files من عندنا فهنعمل server object وبردو نشغله فى thread جديد قشطة؟

#listen for connections in background..
		 self.addr=('', self.listeningPort)
		 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()

جميل بما إنى على جهاز واحد فهتحصل مشكلة انى مش هقدر اعمل set ل port معين اربطه بالسرفر لأن بكل بساطة كل ال Peers هيحاولو يربطو على السرفر دا .. فبكل بساطة هنستخدم randint method الموجودة ب random module ونجيب اى random int بس لاحظ إنه يكون فوق ال 1024 وبردو نبلغ بيه الDiscovery Server

self.listeningPort=rnd.randint(8081, 10000)

اولا ال registerAtServer Method

	def registerAtServer(self):
		 msg=("/register", self.alias, self.sharedFiles, self.listeningPort)
		 self.tcpClient.send(serialize(msg))

وهى اول ميثود هيتم إستدعائها بمجرد إنى اعمل connect على السرفر

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: continue
			 if data.lower=="exit": exit()

			 if data.split(" ")[0]=="/fetch":
				 fileneeded=data.split(" ")[1]
				 addr=data.split(" ")[2]
				 tFetchFile=threading.Thread(target=self.fetchFile, args=[addr, fileneeded])
				 tFetchFile.start()
			 else:   
				 msg=self.alias+": "+data
				 self.tcpClient.send(serialize([msg]))

بما إن ال client مش ليه غير وظيفة واحدة بس اللى مش هتتعامل مع ال server وهى ال fetching فهنختبرها الأول إذا هى المطلوبة او لأ.. فى حال آه نبدأها فى thread جديد خاص بالتعامل معاها :D لو لأ تبقة مجرد رسالة او امر زى إستعلام او تغيير بيانات فهنبعته للسرفر والسرفر يحلله

نهدل رسايل ال server فى thread هيستخدم ال serverToClientHandler method

	 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

عملية ال fetching بكل بساطة هنتعامل معاها كالتالى

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.sendall(serialize(("/fetch", fileneeded)))
		 tDownloadFile=threading.Thread(target=self.downloadFile, args=[fetchTCPClient, fileneeded])
		 tDownloadFile.start()

ونبدأ فيها thread جديد لل download بيستخدم ال downloadFile method و هيباصى ال tcpClient, الفايل المطلوب ك args ليها

def downloadFile(self, fetchTCPClient, fileneeded):

		 f=file(fileneeded, "wb")
		 while True:
			 try:
				 buf=fetchTCPClient.recv(self.BUF)
				 if not buf:
					 break
				 f.write(buf)
			 except EOFError, eofErr:
				 print "EOFError: ", eofErr
			 except Exception, e:
				 print "Error: ", e
				 break
		 print "File Downloaded!"
		 f.close()
		 fetchTCPClient.close()

جميل جدا احنا كدا شبه خلصنا .. ناقص شئ واحد بس وهو التعامل مع ال clients اللى عايزين يحملو فايلات مننا -خليك فاكر إننا already مشغلين thread خاص بالlistening للطلبات :)

self.tListening=threading.Thread(target=self.listeningHandler, args=[])
		 self.tListening.start()

جميل ال thread دا بيستخدم listeningHandler method وال method دى مش هتاخد args

	 def listeningHandler(self):
		 self.listener.listen(5)
		 while True:
			 clientSocket, clientAddr=self.listener.accept()
			 tClientHandling=threading.Thread(target=self.clientHandler, args=[clientSocket])
			 tClientHandling.start()

محتاجين إنها تكون Multi-threaded عشان مش نربط نفسنا مع مستخدم واحد بس

فهنعمل thread جديد يهندل كل client يعمل connect على ال internal server

  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)
				 print "File Request: ", fileneeded
				 f=file(fileneeded, "rb")
				 while True:
					 try:
						 buf=f.read(self.BUF)
						 if not buf:
							 break
						 clientSocket.send(buf)
					 except Exception, e:
						 print "Error: ", e
						 break

				 f.close()
				 clientSocket.close()
				 print "Copied!"

وبس كدا :D

	
 if __name__=="__main__":
	 alias=raw_input("Alias: ")
	 sharedFiles=os.listdir(os.getcwd())
	 peer=Peer(alias, ('localhost', 8080), sharedFiles)

طبعا تقدر تظبطها بحيث إنك تباصى ال addr الخاص بال server من ال command line او حتى من prompt :)

ملحوظة هامة جدا: ياريت تخلى بالك من كل مسافة بتكتبها فى الكود :tooth:

الأكواد

Discovery Server

#!bin/python

 import socket
 import sys
 import os
 import threading
 from utils import serialize, deserialize, PeerInfo
 import sqlite3


 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=2048

	 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]
					 print "Cmd: ", cmd
					 # 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":
							 newNick=recvd.split(" ")[1]
							 print "Attemp to changed the alias for: ", formatedAddress, " to: ", newNick

							 if self.isValidAlias(newNick):
								 self.setNick(formatedAddress, newNick)
								 print "Sending /setnickresult TRUE"
								 clientSocket.send(serialize(["/setnickresult TRUE"]))
							 else:
								 print "Sending /setnickresult FALSE"
								 clientSocket.send(serialize(["/setnickresult FALSE"]))
				except Exception,e :
					 print "Error: ", e


		except Exception, e:
				  print "Data: ", data
				  print "Error: ", e
				  self.alSocks.remove(clientSocket)

	 def isValidAlias(self, alias):
		 for pInfo in self.db.values():
			 if pInfo.alias==alias:
				 return False
		 return True


	 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(8500)

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=1024
		 self.listeningPort=rnd.randint(8081, 10000)
		 self.pInfo=PeerInfo(self.alias, self.sharedFiles, self.listeningPort) 


		 print "\nConnected to server..."
		 self.tClientToServer=threading.Thread(target=self.clientToServerHandler, args=[])
		 self.tClientToServer.start()


		 #listen for connections in background..
		 self.addr=('', self.listeningPort)
		 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 setNick(self, to):
		 self.alias=to

	 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: continue
			 data=data.lower()
			 if data=="exit": exit()
			 if data.split(" ")[0]=="/setnick":
				 self.__tempNick=data.split(" ")[1]
				 print "Temp Nick: ",self.__tempNick	   
			 if data.split(" ")[0]=="/fetch":
				 fileneeded=data.split(" ")[1]
				 addr=data.split(" ")[2]
				 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']
				 recvd=data[0]
				 if data[0]=="/setnickresult FALSE":
					 print "Cannot change the nick to: ", self.__tempNick
				 elif data[0]=="/setnickresult TRUE":
					 print "Nick changed to: ", self.__tempNick
					 self.setNick(self.__tempNick)


				 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.sendall(serialize(("/fetch", fileneeded)))
		 tDownloadFile=threading.Thread(target=self.downloadFile, args=[fetchTCPClient, fileneeded])
		 tDownloadFile.start()

	 def downloadFile(self, fetchTCPClient, fileneeded):
 ##	   try:
 ##		   f=file(fileneeded, "wb")
 ##		   while True: 
 ##					dataRcvd=fetchTCPClient.recv(self.BUF)
 ##					if not dataRcvd: break
 ##					f.write(dataRcvd)
 ##
 ##		   print "File Downloaded!" 
 ##
 ##	   except Exception, e:
 ##		   print "Error: ", e
 ##		   
 ##	   finally:
 ##		   print "Closing the file.."
 ##		   fetchTCPClient.close()
 ##		   f.close()
		 f=file(fileneeded, "wb")
		 while True:
			 try:
				 buf=fetchTCPClient.recv(self.BUF)
				 if not buf:
					 break
				 f.write(buf)
			 except EOFError, eofErr:
				 print "EOFError: ", eofErr
			 except Exception, e:
				 print "Error: ", e
				 break
		 print "File Downloaded!"
		 f.close()
		 fetchTCPClient.close()





	 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)
				 print "File Request: ", fileneeded
				 f=file(fileneeded, "rb")
				 while True:
					 try:
						 buf=f.read(self.BUF)
						 if not buf:
							 break
						 clientSocket.send(buf)
					 except Exception, e:
						 print "Error: ", e
						 break

				 f.close()
				 clientSocket.close()
				 print "Copied!"



 if __name__=="__main__":
	 alias=raw_input("Alias: ")
	 sharedFiles=os.listdir(os.getcwd())
	 peer=Peer(alias, ('localhost', 8080), sharedFiles)

Utils:

 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("ahmed", [1, 2, 3 ,4], 80)
	 print p
	 print "alias: ",p.alias
	 print "files: ", p.sharedFiles
	 print "port : ", p.listeningPort

ملحوظة مهمة بردو: Python ومعظم اللغات بتقدملك Libs تساعدك فى الموضوع دا لأقصى درجة ولكن انا عن نفسى حبيت اكتبه من الصفر ف feel free to google for more!

وفى اكتر من تكنيك لكن انا عن نفسى بحب الThreads واخد بالك ياستورم :tooth:

EDIT:

@الناس اللى هتعدل على البرنامج

TODO List:

1- استخدم simple db engine

2- وفر خاصية ال resume للملفات اللى بتتحمل

3- فعل ال LOG "استفيد من الرسايل اللى بيتعملها print" على السرفر :D

4- استخدم ال Discovery Server ك Web Service

5- اكيد GUI

6- اوامر اكتر لهندلة الPeerInfo وامتيازات خاصة

s1hx5.th.jpg

--Ahmed Youssef

(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#2

مقال جميل/ سلمت يداك اخي

قطرة الماء تـثـقب الحجر.. لا بالعنف. لكن بتكرار المحاولة

at4re.gif

منتديات الفريق العربي للهندسة العكسية 不喜欢的勿入! www.at4re.com

#3

تسلم dj-siba وان شاء الله الجزء التانى هيكون ممتع اكتر :)

(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#4
اقتباس
مقال جميل/ سلمت يداك اخي

مواضيع مشابهة