PDA

View Full Version : سوال: ارتباط دو طرفه همزمان بین کلاینت و سرور



hamid1642
شنبه 07 تیر 1393, 08:55 صبح
با سلام
من میخوام یه وب سایت با زبان php داشته باشم که باهاش بتونم ارتباط دو طرفه همزمان بین کلاینت و سرور رو داشته باشم.
و نمیخوام از وب سوکت اسافاده کنم، چون سرور هایی که وب سوکت رو ساپورت میکنه، محدود هست.
کسی هست که من رو راهنمایی کنه؟
با تشکر

eshpilen
شنبه 07 تیر 1393, 09:42 صبح
چون سرور هایی که وب سوکت رو ساپورت میکنه، محدود هست

تحقیق کردی در این مورد؟
اطلاعات و آمارش رو بده.

hamid1642
شنبه 07 تیر 1393, 10:32 صبح
من میخوام از طریق وب سایت بتونم یک رله رو که به میکروکنترلر متصل هست رو کنترل کنم. به میکرو کنترلر یه ماژول sim900 وصل کردم که از طریق gprs میشه به اینترنت متصل شد.
منتهی این ماژول فقط از طریق پروتکل tcp و udp میشه به اینترنت وصل شد.
در این زمینه بسیار تحقیق کردم.
چند تا راه حل پیدا کردم ولی هیچ کدومش به کارم نمیاد.
1- استفاده از وب سوکت: با وب سوکت میشه راحت این کار رو انجام داد ولی لازمه که یک آی پی اختصاصی و یک سرور شخصی داشته باشیم تا بتوانیم سوکت سرور رو اجرا کنیم.
وب سوکت بر روی هاست های معمولی اجرا نمیشه.
2- استفاده از node.js که باز هم بر روی هاست های معمولی اجرا نمیشه.
3- استفاده از ajax که باز هم به درد من نمیخوره. چون برای اجرای آن به یک مرورگر اینترنت نیاز داریم.
4- استفاده از روش long pooling: با این روش میشه جواب گرفت. فقط باید به صورت پی در پی از طریق ماژول به سرور وصل شد و دیتای جدید رو خوند. که اینجوی هزینه اتصال زیاد میشه. چون در هر بار به سرور وصل میشیم و دیتا رو میخونیم و ارتباط قطع میشه. و باید مجددا کانکت بشیم.
5- روش push to client: که در این زمینه مطالعه کردم و چیزی نصیبم نشد.
در کل اگه بشه بار اول به سورو وصل بشیم و تا زمانی که دیتا تغییر نکنه، بتونیم کانکشن رو باز نگه داریم، میشه این کار وروانجام داد. ولی نمی دونم چه جوری. چون در حالت عادی بلافاصله پس از اتصال دیتا دریافت میشه و کانکشن قطع میشه و با توجه به اینکه آی پی سیم کارت ها، تغییر میکنه، پس از قطع اتصال هیچ دسترسی به سیم کارت نداریم.
البته چیزی که گفتم قابل انجام هست. جوری که من تحقیق کردم، این کار با برنامه نویسی تحت وب قابل انجام هست و در ایران نیز این کار انجام شده. فقط هزینه کد آن بسیار زیاد و در حد 600 هزار تومن هست.
برای آشنایی بیشتر سری به لینک زیر بزنید:
http://afshinalizadeh.com/%D8%AA%D8%A8%D8%A7%D8%AF%D9%84-%D8%AF%D8%A7%D8%AF%D9%87-%D8%A8%D8%A7-%D9%BE%D8%B1%D9%88%D8%AA%DA%A9%D9%84-gprs/
لطفا اگه میتونین راهنمایی کنین.

eshpilen
شنبه 07 تیر 1393, 11:49 صبح
خب اون اسکریپت PHP که سمت سرور هست اتصال رو میتونه باز نگه داره.
این کد رو هم ابتداش بذارید که زود timeout نشه:

set_time_limit(0);
یک روش comet که بهش نوع streaming میگن همینطور کار میکنه: http://www.hamidreza-mz.tk/?p=589
شما سمت سرور هر قطعه داده/دستوری رو که ارسال میکنید بلافاصله پشت سرش این دستورات رو هم:

ob_flush();
flush();
اجرا کنید که باعث میشه خروجی فورا به سمت کلاینت (درمورد شما سوکت TCP در طرف دیگر) ارسال بشه.
در سمت دیگه فقط سوکت پروگرامینگ هست که این داده ها رو بخونید. مشکل خاصی وجود داره؟

البته باید مکانیزمی برای اطلاع از قطع شدن اتصال هم طراحی کنید و درصورت قطع شدن دوباره متصل بشید، چون تضمینی نداره که ارتباط به هر دلیلی منجمله timeout هایی که روی سرور یا کلاینت هست قطع نشه.

hamid1642
دوشنبه 09 تیر 1393, 08:32 صبح
با سلام و تشکر
جوابتون فوق العاده بود و کارمو راه انداخت. فقط اینکه هاست های رایگان set_time_limit(0); ساپورت نمیکنه.

hamid1642
دوشنبه 09 تیر 1393, 13:32 عصر
با سلام
آیا میشه همزمان که داده رو دریافت می کنیم، داده رو ارسال کنیم؟
تو برنامه نویسی سوکت این کار امکان پذیر هست. آیا اینجا هم میشه؟

eshpilen
دوشنبه 09 تیر 1393, 13:54 عصر
خب یه چیزی که توی HTTP1.1 اومد این بود که برای هر درخواست HTTP لزوما یک سوکت جدید ایجاد نشه و بشه سوکت رو باز نگه داشت و برای درخواستهایی که با فاصله زمانی کم ارسال میشن از همون سوکت استفاده کرد. هدر connection: keep-alive معنا و کاربردش همینه.
حالا شما باید روی این تحقیق و تست کنی، احتمالا بشه ازش برای هدفی که میخوای یجوری سوء استفاده کرد!!
ولی منطق سمت سرورش هم فکر میکنم پیچیده تر میشه به این شکل. چون به ازای هر درخواست جدید (با اینکه روی همون سوکت و کانکشن قبلی ارسال میشه) یک نمونهء جدید از اسکریپت PHP مورد نظر اجرا میشه (توی همون فضای پراسس/ترد قبلی نیستی و مثلا متغییرها همه ریست شده هستن).

hamid1642
دوشنبه 16 تیر 1393, 09:06 صبح
با سلام
من نتونستم از کلاینت به سورو دیتا بفرستم!
ارتباط از سمت سرور به کلاینت با راهنمایی جنابعالی به راحتی انجام شد ولی نمی تونم از سوکت tcp به سورو چیزی بفرستم.
هدف من این هست که از سرور به tcp دیتا بفرستم و سپس کلاینت به درخواست سرور جواب بده.

eshpilen
دوشنبه 16 تیر 1393, 09:46 صبح
شاید سرفرصت یکسری تست انجام دادم. با هر دوی پایتون و PHP میتونم سمت کلاینت و سوکتش بنویسم؛ بنظرت کدومش بهتره؟ فکر کنم پایتون بهتر باشه چون محیط جدایی میشه. پایتون داری و میتونی باهاش کنار بیای؟

hamid1642
دوشنبه 16 تیر 1393, 10:43 صبح
ممنون از جواب های مناسبتون و تشکر ویژه از اینکه زود جواب میدید.
برای اینکه این پروژه به جواب برسه من حاضرم پایتون هم یاد بگیرم.
فقط چیزی که هست در سمت کلاینت فقط Tcp داریم و مرورگر وب نداریم. فقط هم با پورت 80 می تونیم کار کنیم.

eshpilen
دوشنبه 16 تیر 1393, 11:24 صبح
مرورگرها هم تاجاییکه میدونم دارن از یک کانکشن TCP برای ارسال چند درخواست و دریافت چند پاسخ HTTP استفاده میکنن، پس حتما باید شدنی باشه. فقط باید جزییات فنیش رو دربیاریم و تست کنیم.

eshpilen
سه شنبه 17 تیر 1393, 08:30 صبح
فولدر test را در ریشهء www قرار بدید.
آدرس http://localhost/test/client.php رو در مرورگر وارد کنید.
نتیجه اجرای برنامه دیده میشه.
اگر داخل client.php رو نگاه کنید، ما فقط یک سوکت رو فقط یک بار با fsockopen("localhost", 80)‎ باز کردیم، بعد با استفاده از همون سوکت در مجموع 3 درخواست HTTP ارسال کردیم و 3 پاسخ رو دریافت کردیم.
اما با تست هایی که انجام دادم متوجه شدم یک مشکل/محدودیت وجود داره برای کاربرد مورد نظر شما! اونم اینکه، شما میتونید یک درخواست HTTP جدید رو هر موقعی ارسال کنید، اما تا وقتی که اجرای اسکریپتی که برای پردازش درخواست قبلی run شده تموم نشه، درخواست جدید در سرور پردازش نمیشه.
بطور مثال بواسطهء خط 28، ما قبل از اینکه آخرین خروجی server.php، یعنی req1: data3 رو دریافت کنیم، با دستور break از حلقهء دریافت خارج شده و درخواست جدیدی رو روی سوکت ارسال میکنیم، اما در مرورگر مشاهده میکنیم که تا وقتی که آخرین خروجی دریافت نشده و اجرای درخواست قبلی تموم نشده، پردازش درخواست جدید پردازش شروع نمیشه.
بسته به برنامهء شما ممکنه از یک راه خاصی برای کنار اومدن با این محدودیت استفاده کنید.
ظاهرا شما در سمت سرور یک حلقهء بی پایان دارید که درش فرمانهایی رو به کلاینت ارسال میکنید. پس تا وقتی این حلقه یجوری متوقف نشه، اجرای درخواست جاری ادامه پیدا میکنه و بنابراین کلاینت نمیتونه اطلاعات جدیدی رو از طریق درخواست جدیدی رو همون سوکت به سرور ارسال کنه (ارسال میشه، ولی سرور پردازش نمیکنه).
باید دید که شما چه مواقعی ممکنه اطلاعاتی رو بخواید از کلاینت به سرور بفرستید، و میخواید دریافت و پردازش این اطلاعات در سمت سرور تا چه حد سریع باشه. مثلا اگر نیازی نیست که این مسئله بصورت real time صورت بگیره، میتونید اجرای حلقه رو با فواصل زمانی مشخصی پایان بدید، مثلا هر 10 ثانیه، و البته میتونید این مسئله را قبل از خروج به اطلاع کلاینت برسانید تا کلاینت بلافاصله درخواست بعدی را ارسال کند (بخصوص که اگر تا مدتی این کار را نکند ممکن است کانکشن timeout شود) و اگر اطلاعات جدیدی برای ارسال دارد از این طریق آن را برای سرور بفرستد.
راستی آیا میتوانید از سمت کلاینت همزمان دو کانکشن TCP داشته باشید؟ اگر اینطور باشد، میتوانید از یک کانکشن TCP دیگر برای اطلاع دادن به سرور هر زمان که کلاینت میخواهد اطلاعات جدیدی را ارسال کند استفاده کنید. به این شکل، ارسال اطلاعات از سمت کلاینت و دریافت و پردازش آن در سمت سرور میتواند بسیار سریعتر صورت بگیرد.
اما یک مسئله هم در این ارتباط این است که اگر کلاینت ارسال اطلاعات زیاد داشته باشد، یعنی در فواصل زمانی کوتاه مدام بخواهد اطلاعات جدیدی ارسال کند (مثلا در هر ثانیه یک بار)، در نتیجه در سمت سرور برنامهء ما مدام در فواصل زمانی کوتاه باید اجرا شود و خاتمه یابد، که این ممکن است به افزایش بار سرور و شاید همچنین کند شدن ارتباطات بیانجامد (به علت هزینه و کندی احتمالی خاتمه و ایجاد مداوم پراسسها/تردهای جدید در فواصل زمانی کوتاه). البته باید در عمل هم دید که تا چه حد تاثیر دارد و مشکل ایجاد میکند یا نه.

eshpilen
سه شنبه 17 تیر 1393, 08:59 صبح
چند نکته دیگر:
- دقت کنید که در آخرین درخواست از Connection: Close استفاده کردیم که باعث میشه وقتی پردازش آخرین درخواست تموم شد، کانکشن TCP بلافاصله بسته بشه. ولی شما در برنامتون به گمانم همیشه باید از Keep-Alive استفاده کنید.
- هدر Keep-Alive: timeout=5 که در پاسخهای سرور ارسال میشه داره میگه که timeout سوکت 5 ثانیه است (بسته به کانفیگ ممکنه این مقدار روی سرورهای دیگر متفاوت باشه). یعنی اگر پس از تمام شدن پردازش آخرین درخواست (خاتمهء اسکریپت)، به مدت 5 ثانیه درخواست جدیدی از کلاینت به سرور روی اون سوکت ارسال نشه، سوکت از سمت سرور بسته خواهد شد.
- فکر میکنم تعداد درخواستهای ارسالی روی یک سوکت هم محدودیت داشته باشه (احتمالا اون پارامتر max=99 داره این رو میگه). بهرحال هم که شما همیشه باید احتمال بسته شدن سوکت توسط عوامل دیگر رو هم درنظر بگیرید و چک کنید و اگر سوکت بسته شده بود کانکشن جدیدی ایجاد کنید.

hamid1642
سه شنبه 17 تیر 1393, 12:26 عصر
خیلی خیلی ازتون ممنونم.
اصلا باورم نمیشه که اینتقدر زود جوابمو دادید.
فکر میکنم امکان ارسال دو کانکشن tcp وجود داشته باشه.
این برنامه ای که نوشته بودید قسمت کلاینت رو نمیشه از طریق tcp و telnet پیاده سازی کرد.
دو تا مشکل اساسی من دارم:
یکی اینه در http 1.1 هر موقع keep alive استفاده کردم، باز هم بعد از چند ثانیه کاقطع میشه.
دوم اینکه من در پروژه comet از set_time_limit(0) استفاده میکنم، روی سرور easyphp جواب میده ولی این روی هاست های رایگان جواب نمیده.
آیا هاست های غیر رایگان این دستور رو باز گذاشتن؟
بازم ممنونم از پیگیری هاتون.
امیدوارم همواره موفق باشید.

eshpilen
سه شنبه 17 تیر 1393, 13:35 عصر
این برنامه ای که نوشته بودید قسمت کلاینت رو نمیشه از طریق tcp و telnet پیاده سازی کرد.
client.php داره با سوکت TCP کار میکنه دیگه. من با PHP نوشتم چون دم دست و راحت بود ولی هر زبان دیگری میشه نوشت. telnet هم که یک پروتکل و یک ابزاره؛ زبان برنامه نویسی نیست که میگی باهاش میشه اینو نوشت یا نه. یعنی چی؟ اگر میخوای از هاستهای اشتراکی بتونی برای هدفت استفاده کنی، مجبوری با سوکت TCP وصل بشی به وب سرور و از طریق پروتکل HTTP با برنامت ارتباط برقرار کنی. حالا telnet رو این وسط چطوری چکارش کنیم مثلا؟ :متفکر:


یکی اینه در http 1.1 هر موقع keep alive استفاده کردم، باز هم بعد از چند ثانیه کاقطع میشه.
گفتم که تایم آوت داره. البته این تایم آوت برای موقعی هست که اجرای اسکریپت سمت سرور تموم شده باشه (نه در حلقهء بینهایت). بنابراین اگر میخوای در این مورد ارتباط قطع نشه، باید حداکثر چند ثانیه بعد از تموم شدن اجرای اسکریپت سمت سرور، یک درخواست HTTP جدید روی همون سوکت TCP بفرستی. البته بجز این ممکنه timeout های دیگری در جاهای دیگری هم باشن.


دوم اینکه من در پروژه comet از set_time_limit(0) استفاده میکنم، روی سرور easyphp جواب میده ولی این روی هاست های رایگان جواب نمیده.
آیا هاست های غیر رایگان این دستور رو باز گذاشتن؟
روی یکی دوتا هاست که من تاحالا داشتم تاجاییکه یادمه باز بود. بطور معمول دلیلی نداره ببندن. ولی بازم نباید فقط روی این حساب کرد و باید در برنامه مکانیزم تشخیص قطع شدن ارتباط (و همچنین احتمالا تمهیداتی برای جلوگیری از اون یا طولانی کردنش) و کانکشن مجدد وجود داشته باشه بطور کلی.

بهرحال بنده روشها و ابزار کلی و پایه رو گفتم و نمونه و تستش رو برات گذاشتم و بعضی نکات و راهنمایی ها همچنین. بقیش دیگه جزییات فنی برنامه و محیط و امکانات شماست که باید خودت انجامش بدی. برنامه نویسی اینطور چیزها با اینکه حجم خیلی زیادی نداره اما کار استاندارد و راحتی نیست و برنامه نویس باید دانش و تسلط خوبی داشته باشه در برنامه نویسی سوکت، پروتکل ها، و نکات فنی سطح پایین و خلاصه هرچیزی که نیاز میشه و موارد رو هندل کنه.

hamid1642
چهارشنبه 18 تیر 1393, 10:59 صبح
با سلام
من تونستم تمام موارد رو روی localhost پیاده سازی کنم. ولی روی هاست رایگان کار نمیکنه.
البته فکر میکنم به خاطر دستوراتش هست که روی هاست های رایگان بسته شده.
علاوه بر دستور set_time_limit، دستورات flush هم کار نمیکنه.
در نتیجه هنگامی که comet رو راه اندازی میکنم. بعد از 30 ثانیه time out میشه و سپس خروجی به یکجا(مثل حال عادی) به کلاینت ارسال میشه.(هاست zgig.ir)
ولی روی سرور مجازی کاملا جواب میده و درست کار میکنه.