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

منع تشغيل أكثر من نسخه من برنامجك

بدأه Wajdy Essam في 19 أبريل 2008 · 8 رد · 1,044 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ،

في بعض الأحيان قد نجبر المستخدم على عدم فتح أكثر من نسخه من البرنامج ، وخاصه في البرامج التي تتصل مع قاعده البيانات والتي لا تقوم بعمل Commit الا مثلا عند الخروج من البرنامج ...... أو أي برنامج أخر مثلا مثل برامج المنبهات والتي تعمل كل مده معينه .. أو لأي سبب أخر .

ولأن أي برنامج نقوم بتشغليه فسوف يعمل على VM خاصه به ، لذلك لا توجد طريقه مباشره لهذا الأمر .. .

وسوف نستعرض اشهر طريقتين ، أحدهما عن طريق socket (لا تستغرب :) ) ، والأخرى عن طريق FileLocking .

الطريقه الأولى The socket technique :

هذه الطريقه فكرتها كالأتي ، هو عندما نشغل البرنامج لأول مره نقوم بتشغيل Server برقم بورت معين مثلا 2000 ، ويكون هذا السيرفر دليل على أن هناك نسخه تعمل . في حال شغلت نسخه أخرى من البرنامج نقوم بالاتصال بالسيرفر فاذا أتصل فهذا معناه أن هناك نسخه تعمل وهنا سوف أغلق البرنامج الجديد .

أي الخوارزميه كالأتي ،

- قم بالأتصال بالسيرفر بالمنفذ 2000 ، في حال أتصل فمعناه أنه هناك نسخه تعمل ، فقم الأن باغلاق النسخه الجديده .

- في حال لم يتصل البرنامج بالسيرفر (معناه أنه لا يوجد سيرفر يعمل ) سوف ينفذ جزء Exception وهنا سوف نقوم بتشغيل السيرفر من داخل الException .

كود بسيط للسيرفر :

// This MonitorServer will start when you open myApp

import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;

public class MonitorServer extends Thread
{
	private ServerSocket serverSocket;
	private Socket socket;
	private static final int PORT = 5000;

	public void run ()
	{
		try
		{
			serverSocket = new ServerSocket(PORT);

			while ( true )
			{
				socket = serverSocket.accept();		// get client
				socket.close();
			}
		}
		catch ( IOException e)
		{
			e.printStackTrace();
		}
	}
}

وهذا كود البرنامج :

// romansy

import java.net.Socket;
import java.io.IOException;
import javax.swing.JOptionPane;

public class MyApp
{
	public static void main (String args[])
	{
		try
		{
			Socket socket = new Socket("localhost",5000);
			// if get connection in mean that server is open , it mean that is client is opening

			JOptionPane.showMessageDialog(null,"Their is Opening Vesrion of this Program",
				"Cannot Open More Than One Version",JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		catch (IOException e)
		{
			// here the server is not opening  , so we open it now
			MonitorServer server = new MonitorServer();
			server.start();
		}

		// here application code
		// good Luck 
	}
}

نأخذ مثال لتطبيق الفكره ، وهو لبرنامج مفكره بسيط يقوم بحفظ وقرائه ملفات txt وبه خاصيه نسخ ولصق ... المهم أنظر الصوره التاليه وستجد أننا نستطيع تشغيل أكثر من نسخه .. نريد الأن اضافه الطريقه التي تعلمناه قبل قليل عليه ...

793904-155.jpg

ننظر الى الداله الرئيسيه :

public class JNotePad 
{
	public static void main (String args[])
	{
		JNotePadFrame app = new JNotePadFrame();
		app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		app.setVisible(true);
	}
}

نقوم الأن باضافه كود الأتصال في البدايه -أول سطر في البرنامج- :

public static void main (String args[])
	{
		try
		{
			Socket socket = new Socket("localhost",5000);
			// if get connection in mean that server is open , it mean that is client is opening

			JOptionPane.showMessageDialog(null,"Their is Opening Vesrion of this Program",
				"Cannot Open More Than One Version",JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		catch (IOException e)
		{
			// here the server is not opening  , so we open it now
			MonitorServer server = new MonitorServer();
			server.start();
		}

		JNotePadFrame app = new JNotePadFrame();
		app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		app.setVisible(true);
	}

وها هو برنامجنا الأن يصيح عندما تقوم بتشغيل أكثر من نسخه :

793904-156.jpg

على العموم ، الطريقه ليست سريعه كما في الطريقه التاليه ، ولكنها تفي بالغرض !!

الطريقه الثانيه The file lock technique :

تعتمد هذه الطريقه على java.nio.channels وطريقتها هي انشاء ملف في مجلد user.home وعمل lock عليه channel.tryLock() ، وفي حاله لم يستطع البرنامج عمل lock وذلك بسبب وجود نسخه تعمل سوف يحصل Exception من نوع OverlappingFileLockException . وعند اغلاق البرنامج يجب أن نزيح هذا المقبض على الملف وذلك باستخدام shutdown hook .

على ما أظن الكلام غير واضح :) ، والسبب يرجع لكوني لم أتعامل مع java.nio.channels من قبل . على العموم هذا الكود ، قم بتشغيله وستجد أنه أسرع من الطريقه الأولى ..

الملف الأول JustOneLock وهو الخاص بوضع الLock . ونستطيع استخدامه مع أي برنامج أخر بلا تغيير .

import java.io.*;
import java.nio.channels.*;

public class JustOneLock
{
	private String appName;
	private File file;
	private FileChannel channel;
	private FileLock lock;

	public JustOneLock(String appName)
	{
		this.appName = appName;
	}

	public boolean isAppActive() 
	{
		try 
		{
			file = new File(System.getProperty("user.home"), appName + ".tmp");
			channel = new RandomAccessFile(file, "rw").getChannel();

			try 
			{
				lock = channel.tryLock();
			}
			catch (OverlappingFileLockException e) 
			{
				// already locked
				closeLock();
				return true;
			}

			if (lock == null) 
			{
				closeLock();
				return true;
			}

			Runtime.getRuntime().addShutdownHook
			(
				new Thread() 
				{
					// destroy the lock when the JVM is closing
					public void run() 
					{
						closeLock();
						deleteFile();
					}
				}
			);

			return false;
		}
		catch (Exception e) 
		{
			closeLock();
			return true;
		}
	}

	private void closeLock()
	{
		try 
		{ 
			lock.release();
		}
		catch (Exception e) { }

		try 
		{
			channel.close(); 
		}
		catch (Exception e) { }
	}

	private void deleteFile()
	{
		try 
		{ 
			file.delete(); 
		}
		catch (Exception e) { }
	}
}

برنامجنا الذي نريده أن يعمل مره واحده :

public class JustOneTest 
{
	public static void main(String[] args) 
	{
		new JustOneTest().test();
	}

	void test() 
	{
		JustOneLock ua = new JustOneLock("JustOneId");

		if (ua.isAppActive()) 
		{
			System.out.println("Already active.");
				System.exit(1);
		}
		else 
		{
			System.out.println("NOT already active.");
			try 
			{
				while(true) 
				{
					try 
					{ 
						System.out.print("."); 
						Thread.sleep(5 * 60); 
					}
					catch(Exception e)
					{ e.printStackTrace(); }
				}
			}
			catch (Exception e) { }
		}
	}
}

نقوم بالتعديل الأن في برنامج المفكره لكي نستخدم هذ الطريقه ، وسوف تكون الداله الرئيسيه بهذا الشكل :

public static void main (String args[])
	{
		JustOneLock ua = new JustOneLock("JustOneId");

		if (ua.isAppActive()) 
		{
			JOptionPane.showMessageDialog(null,"Their is Opening Vesrion of this Program","Cannot Open More Than One Version",
					JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}

		JNotePadFrame app = new JNotePadFrame();
		app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		app.setVisible(true);
	}

أتمنى أن لا يكون الموضوع مكرر ، وفي حال كان كذلك يمكن للمشرف حذف الموضوع .....

البرنامج المفكره في المرفقات .

الى اللقاء .

JNotePad_Using_Socket_Technique.rar

JNotePad_Using_FileLocking.rar

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#2

أكره أن أكون سمجاً أخي رومانسي

لكن فعلياً هناك نمط الورقة الوحيدة Singleton Pattern

والذي يتكفل بنفس المهمة دون أي حاجة إلى عمليات التزامن على ملفات

أو فتح منافذ

لكن الأفكار جميلة قد تفيد في شيء آخر

كل التحية لك أخي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#3

حياك الله أخي الكريم علاء ،

بالنسبه للـ Singleton Pattern فصحيح أنه يمنع من عمل أكثر من كائن لنفس الكلاس في الـ VM الحالي ، ولكن لن نستطيع منع البرنامج من التشغيل أكثر مره ، والسبب أنه كما ذكرت من البدايه أن أي برنامج يعمل في VM خاصه به . لذلك باستخدام هذا النمط سوف نستطيع تشغيل البرنامج أكثر من مره ، ولكن لن تستطيع عمل أكثر من كائن له ..

قمت بتجربه الكود التالي ، وأستطعت تشغيل البرنامج أكثر من مره ..

class Singleton{

	private static Singleton singletonObject;

	/** A private Constructor prevents any other class from instantiating. */
	private Singleton(){
		  //	 Optional Code
	}

	public static synchronized Singleton getSingletonObject()
	{
		if (singletonObject == null){
			singletonObject = new Singleton();
		}
		return singletonObject;
	}

	public Object clone()throws CloneNotSupportedException
	{
		throw new CloneNotSupportedException(); 
	}

}

public class SingletonObjectDemo{
	public static void main(String args[]){
//		Singleton obj = new Singleton();	Compilation error not allowed

		//create the Singleton Object..
		Singleton obj = Singleton.getSingletonObject();

		// Your Business Logic
		System.out.println("Singleton object obtained");


		try
		{
			Thread.sleep(30000);
		}
		catch (Exception e)
		{	}

	}
}

تحياتي لك .

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#4

لا يمكن أن يحصل ذلك إطلاقاً

معنى أن لا يكون من الكائن إلا نسخة واحدة

أنك لن تستطيع أن تقوم بتشغيل البرنامج أكثر من مرة واحدة

هل هناك إمكانية أن تعرض البرنامج الذي قمت به كاملاً؟

فربما أكون مخطئ فأتعلم

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#5

بارك الله فيكم أخواني علاء و ورومنسي على أفكاركم الممتعة و المفيدة حقا....

#6

ربما تعاني الطريقة الاولى من بعض المشاكل الامنية بخصوص فتح المنفذ

و اجد الطريقة الثانية فعالة اكثر و لكن هل يمكن ان تتعرض لمشاكل امنية بخصوص صلاحية كتابة الملفات

Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why

#7

سلام عليكم ،،

أهلا أخ علاء ،

اقتباس
معنى أن لا يكون من الكائن إلا نسخة واحدة

أنك لن تستطيع أن تقوم بتشغيل البرنامج أكثر من مرة واحدة

كلام شبه صحيح ، وذلك لأني ذكرت يا أخ علاء أن أي برنامج نقوم بتشغيله يعمل على JVM خاصه فيه .... ولنفرض أن البرنامج الأول قمنا بانشاء الكائن A ، هنا لن نستطيع أنشاء كائن أخر A في نفس البرنامج الأول ، والسبب يعود كما تعلم لأننا طبقنا النمط Singleton . لكن في حال شغلنا برنامج ثاني فسوف نستطيع أنشاء الكائن A حتى لو كان الكائن A في البرنامج الأول مازال يعمل ، والسبب أن لكل برنامج VM خاصه فيه ، لذلك لا يوجد أي رابط هنا بين البرنامج الأول والثاني .

لكي أثبت صحه الكلام ، تفضل الكود التالي ، وفيه الكلاس SingletonGUI يقوم بعمل واجهه فارغه ، الان أول مره سوف نستطيع تشغيل هذا الكائن ، وبعدها بعد ثانتين سوف لن نستطيع انشاء نفس الواجهه وذلك لأن الأولى ما زالت تعمل . (طبعا أنت متفق معي الى هنا تماما) .

الان قم بتشغيل برنامج ثاني مع الأول ، وستجد أن الواجهه SingletonGUI تم انشائها مرتان ، مره في البرنامج الأول ، ومره في الثاني ... لانه لا توجد أي علاقه بين الأثنين (البرنامج الأول والثاني).

// SingleronPattern Test

import javax.swing.*;

public class SingletonPattern
{
	public static void main (String args[])
	{
		SingletonGUI app = SingletonGUI.getInstance();

		if ( app == null )
			JOptionPane.showMessageDialog(null,"Cannot Open More Than One Object",
				"There in Running Object Now",JOptionPane.ERROR_MESSAGE);

		// wait 2 second
		try
		{
			Thread.sleep(3000);
		}
		catch ( InterruptedException e)
		{	}

		SingletonGUI app2 = SingletonGUI.getInstance();

		if ( app2 == null )
			JOptionPane.showMessageDialog(null,"Cannot Open More Than One Object",
				"There in Running Object Now",JOptionPane.ERROR_MESSAGE);

	}
}

class SingletonGUI extends JFrame
{
	static boolean instanceFlag = false;

	private SingletonGUI ()
	{
		setTitle("Open Frame");
		setSize(300,300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public static SingletonGUI getInstance ()
	{
		if ( instanceFlag == false )
		{
			instanceFlag = true;
			return new SingletonGUI();
		}
		else
			return null;
	}
}

بالنسبه لأخ رامي ، فالطريقه الأولى امنه ولا يوجد مخاوف من أن يتصل كلاينت أخر بهذا السيرفر المفتوح ، لأننا مباشره سوف نقوم بغلق السوكت بعد الأتصال ... لذلك حتى لو أتصل بنا عميل لبرنامج أختراق مثلا Sub7 ، فلا توجد مشكله لأننا سوف نغلق السوكت مباشره بعد الأتصال . ولكن تبقى العمليه بطيئه عند التشغيل حيث كل ما نريد أن نشغل البرنامج فسوف يقوم بالأتصال بالسيرفر ، وهذا يأخذ وقتا ولو قليلا .

أما الطريقه الثانيه ، فلا علم لي بمدى تعرضها للمشاكل في صلاحيات الملف ، على العموم سأحاول أن أقرأ في هذا الخصوص -ان توفر لي وقت - وسأكتب ما توصلت اليه .

وهناك مكتبه JUnique ، تصفحتها بشكل سريع وهي تعتمد على أيضا مفهوم Locking ، بالاضافه الى وجود طريقه للتخاطب بين مختلف الJVM التي ينشئها كل برنامج .

اقتباس
The JUnique library can perform cross-JVM lock operations. It is mainly intended to prevent a user to run simultaneously more instances of the same Java application, and it also offers a communication layer enabling message exchange between different JVMs.

JUnique is based on a user related cross-JVM exclusive lock concept. Suppose you want to avoid your Java desktop application to be started more than once by the same user. When the main() method of your application is called, you can require to JUnique a lock on a certain ID, i.e. myapplicationid. At the first application launch that ID will be surely available, and so the lock will be taken. The obtained lock can be explicitly released with a JUnique.releaseLock() call, otherwise it will be automatically released when JVM halts. If another JVM instance (or even the same one) will try to impose a lock on the same ID, JUnique will return with an AlreadyLockedException, notifying the instance that another one is currently running. Then the second instance can choose to abort its start sequence, and optionally it can send one or more messages to the active one before exiting

يمكنكم تحميل المكتبه والـ Doc الخاص بها بالأضافه الى عده أمثله عليها من هنا :

http://www.sauronsoftware.it/projects/junique/download.php

تحياتي لكم :) .

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#8

لا انا اقصد اكثر من هذا اقصد بانه مجرد عملية فتح المنفذ ستواجه مشاكل عديدة اولها الـJVM نفسها ربما تكون هناك قيود على فتح المنفذ

و الاهم هو الفاير وال الخاص باي نظام او اي برنامج منزل سوف يظهر لك رسائل تحذير بانه البرنامج يقوم بفتح منفذ و هل تريد السماح له ام لا ربما لا يسمح له و يغلق البرنامج !!

Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why

#9

هل لديك علم عن السبب الذي يجعل كل برنامج يعمل على بيئة افتراضية منفصلة؟

هل للموضوع علاقة بالتوافقية؟

في النهاية لا يسعني إلا أن انحني أمام علمك أخ رومانسي

كل التحية لك أخي

م.علاء

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

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

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…