PDA

View Full Version : سوال: کار با چندین جدول مرتبط به هم در یک برنامه تحت شبکه



nadia_1987
جمعه 15 مرداد 1389, 14:46 عصر
سلام.

مشکلم یه ذره خیلی پیچیده است . خواهشا تا آخرش رو بخونید.

اول اینکه اینا جدول هایی هستند که باهاشون سر و کار دارم :


Course ( CsId,CsTittle,MajorId,CsCategory,ThHr,PrHr


که این جدول تمام درس ها با ساعت عملی و تئوری را ذخیره می کند.


Pre-Requisite ( id , PreId, Csid

این جدول تمام پیش نیاز درس ها را در خود ذخیره می کند .




Session (sessionId,CsId,InstId,Year,Sem


این جدول هم تمام درسهایی که در یک سال و ترم مشخص سده ارائه می شود همراه با نام استاد ذخیره می کند.


Mark ( id, StId, Csid , Year , Sem ,Mark


این جدول تمام نمرات دانش آموزان را در خود نگه می دارد.


Registration ( id , StId,CsId,Year ,Sem


این جدول هم تمام درس هایی که دانشجو در یک ترم مشخص شده برداشته است ذخیره می کند ( فرق این جدول با جدول قبلی این است که این جدول شامل درس هایی که دانشجو ممکن است حذف کرده باشد )

و اما مشکل : برنامه من دو قسمت دارد یکی کلاینت و دیگری سرور . که کار با دیتابیس یعنی ذخیره و حذف کردن در سرور اتفاق میافتد . کلاینت اطلاعات را می گیرد و به سرور می فرستد

من ابتدا یک فرم دارم که تمام درس هایی که Major آنها با Major دانشجو یکی است را به او نشان مدهد اما نمی دونم چطور به دانشجو اجازه انتخاب بده به طوری که :

تعداد واحدهایی که انتخاب می کند از 9 کمتر نباشد و از 20 بیشتر نباشد
درسی که انتخاب می کند باید قبلا پیش نیاز آن را با نمره بیشتر از 10 پاس کرده باشد.

؟؟؟؟
خیلی گیجم کرده . نمی دونم درس ها رو دونه دونه بفرستم سرور چک کنه . اگه اینطوریه تعداد واحدها رو چطوری بدونم .
خیلی فکر کردم نتیجه نگرفتم . ممنون می شم مثل همیشه کمکم کنید .

میلاد قاضی پور
شنبه 16 مرداد 1389, 02:25 صبح
هاای کل اینایی که وگقتی یعنی چا ...اوهوآخ ؟ !:بامزه:
دوست عزیز چرا یکی یکی ؟ مشخص نکردید کلاینتش چیکار میکنه ؟چرا توی برنامه سمت کلاینتتون چک نمیکنید اطلاعات وارد شده رو ؟ به نظرتون اینطوری اصولی تر نیست؟



تعداد واحدهایی که انتخاب می کند از 9 کمتر نباشد و از 20 بیشتر نباشد

چرا داده هارو توی آرایه نمیریزید تا راحت مقادیر رو بررسی کنید ؟



درسی که انتخاب می کند باید قبلا پیش نیاز آن را با نمره بیشتر از 10 پاس کرده باشد.

موقع ثبت اطلاعات درس پیش نیاز رو از دیتابیس فراخوانی کنید و نمرشو بررسی کنید. در صورت برقرار نشدن شرط ارور

من نمیدونم مشکلتون تا این حد ساده هست یا من درست متوجه نشدم !

nadia_1987
شنبه 16 مرداد 1389, 02:47 صبح
هاای کل اینایی که وگقتی یعنی چا ...اوهوآخ ؟ !:بامزه:
دوست عزیز چرا یکی یکی ؟ مشخص نکردید کلاینتش چیکار میکنه ؟چرا توی برنامه سمت کلاینتتون چک نمیکنید اطلاعات وارد شده رو ؟ به نظرتون اینطوری اصولی تر نیست؟


چرا داده هارو توی آرایه نمیریزید تا راحت مقادیر رو بررسی کنید ؟


موقع ثبت اطلاعات درس پیش نیاز رو از دیتابیس فراخوانی کنید و نمرشو بررسی کنید. در صورت برقرار نشدن شرط ارور

من نمیدونم مشکلتون تا این حد ساده هست یا من درست متوجه نشدم !

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

یعنی اگه درس ها رو توی آرایه بریزم باید بببرم اون طرف چک کنم که خیلی سخت میشه. چون تحت شبکه بایت می فرستم و بعد باید تفکیک کنم از هم . که من هیچ ایده ای ندارم.

بله . اونطور که شما می فرمایید اصولی تره اما استادم اینطوری خواسته . دیتابیس در سرور باشه و همه تغییرات اونجا اعمال بشه .

حالا دیدید مشکلم راحت نیست . :ناراحت:

BookWorm
شنبه 16 مرداد 1389, 07:16 صبح
سلام ، ببخشید من فضولی می کنم ها ، پایگاه داده شما چیست ؟:متفکر:
من درست متوجه نشدم ، اگر شما برنامه ویندوز می نویسید پس این قضیه سرور و کلاین چیست ؟:گیج:
سرور و کلاینت در برنامه های تحت وب بیشتر مورد بررسی قرار میگیرند که اون هم با آژاکس و ... حل شده .

Rocker
شنبه 16 مرداد 1389, 07:52 صبح
به نظر من بهترین راه حلش اینه که شما یه بانک سبک مثله اکسس رو سمت کلاینتت به عنوان یه محل ذخیره سازی موقت داده ها در نظر بگیری.
برنامه کلاینت داده اش رو توی اون لود میکنه.
یوزر سمت کلاینتت تغییرات رو توی این بانک اکسست ایجاد میکنه و بعد از اینکه تغییراتش به یه حدی رسید با استفاده از یه متدی که برای اینکار در نظر میگیری تمام تغییرات رو به صورت یک جا سمت سرور میفرستی.
یه خورده رو روشی که گفتم فکر کن
جواب میده
من خودم تو برنامه های سوکتم استفاده کردم

Rocker
شنبه 16 مرداد 1389, 07:53 صبح
سلام ، ببخشید من فضولی می کنم ها ، پایگاه داده شما چیست ؟:متفکر:
من درست متوجه نشدم ، اگر شما برنامه ویندوز می نویسید پس این قضیه سرور و کلاین چیست ؟:گیج:
سرور و کلاینت در برنامه های تحت وب بیشتر مورد بررسی قرار میگیرند که اون هم با آژاکس و ... حل شده .

چه ربطی داره ؟؟؟؟:متعجب:

nadia_1987
شنبه 16 مرداد 1389, 14:53 عصر
سلام ، ببخشید من فضولی می کنم ها ، پایگاه داده شما چیست ؟:متفکر:
من درست متوجه نشدم ، اگر شما برنامه ویندوز می نویسید پس این قضیه سرور و کلاین چیست ؟:گیج:
سرور و کلاینت در برنامه های تحت وب بیشتر مورد بررسی قرار میگیرند که اون هم با آژاکس و ... حل شده .

من از sqlserver استفاده میکنم . اما فکر نمی کنم که کلاینت و سرور فقط برای برنامه های وب باشه.
والا من که اطلاعات درستی ندارم . اما خوب پروژه فاینالم هست . استاد خواسته منم گفتم چشم .

nadia_1987
شنبه 16 مرداد 1389, 14:56 عصر
به نظر من بهترین راه حلش اینه که شما یه بانک سبک مثله اکسس رو سمت کلاینتت به عنوان یه محل ذخیره سازی موقت داده ها در نظر بگیری.
برنامه کلاینت داده اش رو توی اون لود میکنه.
یوزر سمت کلاینتت تغییرات رو توی این بانک اکسست ایجاد میکنه و بعد از اینکه تغییراتش به یه حدی رسید با استفاده از یه متدی که برای اینکار در نظر میگیری تمام تغییرات رو به صورت یک جا سمت سرور میفرستی.
یه خورده رو روشی که گفتم فکر کن
جواب میده
من خودم تو برنامه های سوکتم استفاده کردم

مرسی از راهنماییتون . اما اینجوری که کارم دو برابر میشه و این روش تا زمانی خوبه که من بخوام یه سری اطلاعات زیاد از یوزر بگیرم بعد یک جا بفرستم .
اما در رابطه با مشکلی که من دارم . به ازای هر درسی که یوزر انتخاب می کنه باید کلی شرط بررسی کنم . یعنی باید به دیتابیس اصلی سرو کار داشته باشم .

C Sharp
یک شنبه 17 مرداد 1389, 08:04 صبح
اوکی پس اینجور که بوش میاد باید سوکت پروگرمینگ کنید ، درسته ؟

اتفاقا منم پروژه فاینالم همین بود (سوکت پروگرمینگ)

بطور مختصر میگم که اگه جوابم ربطی به مسئله شما نداشت بیخودی وقت شما و دوستان رو نگرفته باشم

کلا تو سیستم سمت کلاینت یکسری اعمال قراره انجام بشه (ثبت نام ، انتخاب واحد و ...)
که هرکدوم نیاز به پروسسهایی تو سرور داره و کلاینت تنها وظیفه گرفتن اطلاعات اولیه از کاربر ، فرستادن اطلاعات به سرور و در نهایت گرفتن جواب از سرور و نمایشش به کاربر رو برعهده داره

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

اگه تا اینجا مسئله شما رو درست فهمیده باشم ، پس راه حل تعریف پروتکل هاست، یعنی به ازای هر عملیات یک پروتکل باید تعریف بشه

البته پیش نیاز این قضیه اینه که شما با اصول شبکه و پروتکل TCP/IP آشنایی داشته باشین

ببخشید طولانی شد ، اگه مقدمه بحثم درسته و نیاز به اطلاعات بیشتر داشتین بگین تا توضیح بیشتری بدم

nadia_1987
یک شنبه 17 مرداد 1389, 13:38 عصر
ببخشید طولانی شد ، اگه مقدمه بحثم درسته و نیاز به اطلاعات بیشتر داشتین بگین تا توضیح بیشتری بدم

مرسی از جوابتون . دقیقا همینه .
اما من که یک سری اطلاعات مثل درستی سال تولد و اینا رو می تونم توی کلاینت چک کنم اما گذروندن دروس پیشنیاز رو که نیاز به دیتابیس دارم رو که نمیتونم چک کنم. یعنی از کلاینت به دیتابیس وصل شوم و چک کنم یا منظور شما چیزه دیگه ای هست ؟



اگه تا اینجا مسئله شما رو درست فهمیده باشم ، پس راه حل تعریف پروتکل هاست، یعنی به ازای هر عملیات یک پروتکل باید تعریف بشه

البته پیش نیاز این قضیه اینه که شما با اصول شبکه و پروتکل TCP/IP آشنایی داشته باشین


من چیزی از اینایی که گفتید نمی دونم . کاملا مبتدی هستم . اگه منبعی دارید که بشه ازش خوند ممنون میشم . یا نمونه برنامه های ساده که با پروتوکل نوشته شده باشه .من فقط در این حد با TCP/IP توی برنامه ام سروکار دارم که از tcplistenr و tcpclient اینا استفاده کردم.

منتظر کمکتون هستم . مرسی

C Sharp
یک شنبه 17 مرداد 1389, 14:13 عصر
منظورم همین چیزیه که شما میگید ، یعنی بخشی از اعتبار سنجی (مثل صحیح بودن تاریخ تولد ، ...) تو بخش کلاینت و بخش مهمتر (رعایت پیش نیازها ، ...) در بخش سرور انجام بشه . تو پست قبلیم جمله بندیم اشتباه بود
(Sorry)

البته منظورم از آشنایی با Tcp/IP فقط جنبه پیاده سازی نیست ، یه جورایی ازش واسه طراحی معماری نرم افزارتون الهام بگیرید
شاید بهتر بود سرویسی مثل Ftp رو مثال میزدم

یه ایراد دیگه تو صحبت قبلیم این بود که گفتم به ازای هر عملیات یک پروتکل ، بهتر بود بگم یک پروتکل

شما واسه اعمال مختلف باید پیام های (Message) متفاوتی به سرور بفرستین ، که هر کدوم فیلد های متفاوتی با دیتا های مختلف رو همراه خودشون از کلاینت به سرور و بر عکس انتقال میدن. حالا اینکه هر پیام چه فیلد هایی داشته باشه و این فیلدها هم تو کلاینت و هم تو سرور چجوری تفسیر بشن رو در قالب پروتکل تعریف میکنن

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

مثلا شما قرارداد میکنید که اولین فیلد هر پیام از نوع int باشه و مقداری که توش قرار داره نشون دهنده نوع پیام هست . حالا واسه عملی مثل درخواست لیست دروس یک رشته ،قرار داد میکنید که مقدار درون فیلد نوع پیام 10 باشه ، و این پیام فیلد دیگه ای به نام فیلد نام رشته داره از نوع string با طول 20 کاراکتر .
بنابراین هر وقت کلاینت بخواد لیست دروس رشته X رو از سرور بگیره باید یه پیام با دو فیلد بسازه : فیلد اول از نوع int با مقدار 10 و فیلد دوم از نوع رشته با طول 20 و مقدار "X". وقتی این پیام به سرور ارسال میشه ، سرور با توجه به فیلد نوع پیام و پروتکلی که تعریف کردین میفهمه که این پیام درخواست لیست دروس رشته X هست

این داستان ادامه دارد D:

nadia_1987
دوشنبه 18 مرداد 1389, 00:01 صبح
پروتکلی که میگم چیز پیچیده و عجیبی نیست ، یعنی قرار داد ، یعنی توافقی بین سرور و کلاینت هایی که میخوان با این سرور تعامل کنن. مثل دستور زبان فارسی که ما واسه قالب بخشیدن به حرفهامون و اینکه حرف هم رو بفهمیم ازش استفاده میکنیم.

این داستان ادامه دارد D:

مرسی از توضیحاتتون . خوب اینا رو که من نیازی نیست جایی کد کنم که؟
اگه فقط قراردادی باشه که من این کار رو کردم. مثلا میدونم اگه یک رشته گرفتم که اولش S بود یعنی کلاینت میخواد یک دانشجو وارد کنه و غیره .

اما خوب این مشکلم رو حل نمیکنه . من چند تا از بخش هاش که ساده بودند . مثل حذف و اضافه یک استاد ، دانش جو ، رشته و غیره رو نوشتم .

اما این مشکلی که اول مطرح کردم مساله سازه .نمی دونم چطور باید حلش کنم.؟؟؟

منتظر ادامه داستان هستم .

C Sharp
دوشنبه 18 مرداد 1389, 07:15 صبح
خوب اینا رو که من نیازی نیست جایی کد کنم که؟

خوب اینه همون منطق برنامه است ، سناریو پروژه شماست ، که مثلا با دستورات کنترلی پیاده ش میکنید.



مثلا میدونم اگه یک رشته گرفتم که اولش S بود یعنی کلاینت میخواد یک دانشجو وارد کنه و غیره .

واسه اینکار روشهای مختلفی وجود داره که یکیش همینه که شما انجام دادین ، ولی روشهای اصولی تر هم هست . اما فعلا گام اول پیاده سازی سیستمیه که نیاز هایی که ازش انتظار دارید رو برآورده کنه



اما این مشکلی که اول مطرح کردم مساله سازه .نمی دونم چطور باید حلش کنم.؟؟؟


اگه درست مشکل اولتون رو در نظر گرفته باشم (فهمیدن اینکه دانشجو حداقل 9 واحد و حداکثر 20 واحد انتخاب کنه و پیش نیازهای هر درس رو گذرونده باشه):

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

رعایت حداقل و حداکثر :
اگه نخواید تو سیستمتون شرایطی مثل معدل A شدن ، ترم آخر بودن، ترم تابستان و ... رو لحاظ کنید ، خود کلاینت میتونه این مسئله رو بررسی کنه ، وگرنه کلاینت باید از سرور درخواست کنه تا حداقل تعداد واحد و حداکثر تعداد واحد قابل انتخاب رو واسش بفرسته

ادامه دارد ... D:

nadia_1987
دوشنبه 18 مرداد 1389, 15:28 عصر
رعایت پیش نیازها :
با فرستادن شماره دانشجویی به سرور و درخواست لیست دروس مجاز برای انتخاب
سرور بر اساس شماره دانشجویی میتونه ببینه دانشجو قبلا چه دروسی رو گذرونده و لیست دروسی که پیش نیازشون رعایت شده رو به کلاینت بفرسته و دانشجو فقط از این لیست قادر به انتخاب واحد هست

D:

مرسی . روش خوبیه. فقط یک سوال : من اگه بخوام لیست درس ها رو بگیرم . اونا رو طبیعتا توی یک ارایه ذخیره میکنم .از طرفی اگه بخوام دیتا رد و بدل کنم بین سرور و کلاینت باید از نوع بایت باشه . من اینو نمیتونم بفهم که اگه یک آرایه بود چطوری اینکا رو بکنم و چطوری اون طرف بتونم تفکیک کنم.

مثلا ببنید اگه بخوام یک دانشجو جدید وارد کنم . اسم و فامیل و رشته رو مثلا از کاربر میگیرم و طول هر کدوم هم به دست میارم و بعدش با string.concat همه ی اینا رو یک سترینگ میکنم می فرستم و اون طرف هم می دونم که خونه ی اول طول اسم است و این طوری کل سترینگ رو تفکیک می کنم.

اما چون تعداد رو میدونم اینکار رو میکنم. اما وقتی ندونم چند تا درس وجود داره که نمی تونم .باید توی آرایه ذخیره کنم که نمی دونم توی اینجور برنامه ها چطوری میشه با آرایه کار کرد ؟

C Sharp
سه شنبه 19 مرداد 1389, 07:45 صبح
خوب ببینید ، میتونید یه فیلد هم واسه طول آرایه توی پیامی که رد و بدل میشه بذارید، یا هر عنصر آرایه رو تو یک پیام جدا بفرستید و با یه فیلدی مثل ایندکس بهم ربطشون بدین .
کاری که خود پروتکل TCP/IP انجام میده شبیه به اینه :
بسته های بزرگ رو به بسته های کوچکتر تقسیم میکنه
هر بسته 2 تا فیلد identification و fragment offset داره
identification رو واسه مشخص کردن اینکه هر بسته متعلق به کدوم دیتاگرام هست استفاده میکنه که تو پروژه شما میتونی همچین فیلدی رو واسه مشخص کردن اینکه متعلق به کدوم پیامه ازش استفاده کنی
fragment offset واسه تعیین ترتیب بسته ها موقع سر هم کردنشون تو گیرنده هست که تو پروژتون معادل همون ایندکس آرایه میتونه باشه

ولی یه راه دیگه واسه انتقال اطلاعات ، استفاده از سریالایز کردن اشیاء هست
یعنی شما با استفاده از یک سریالایزر ، یک آبجکت رو تبدیل به استریم میکنید ، بعد همون استریم رو میتونید داخل شبکه انتقال بدین

مثلا این کلاس Message منه که تو پروژه ام استفاده کردم


[Serializable]
public class Message
{
private MessageType type;
private MessageState state;

private string[] _fields;
private object[] _values;
private int _index;
private string _field;

public MessageType Type
{
get
{
return this.type;
}
}

public MessageState State
{
get
{
return this.state;
}
}

public Message(MessageType type, MessageState state)
{
this.type = type;
this.state = state;
_fields = new string[10];
_values = new object[10];
_index = 0;
}

public void AddField(string field, object value)
{
if (_index == _fields.Length)
throw new IndexOutOfRangeException();

_field = field.Trim().ToUpper();

int index;
if ((index = Array.FindIndex(_fields, Matches)) == -1)
{
_fields[_index] = _field;
_values[_index] = value;
_index++;
}
else
{
_fields[index] = _field;
_values[index] = value;
}
}

private bool Matches(string field)
{
if (field == _field)
return true;
else
return false;
}

public object GetFieldData(string field)
{
_field = field.Trim().ToUpper();
int index;
if ((index = System.Array.FindIndex(_fields, Matches)) == -1)
return null;
else
return _values[index];
}

public void SetValues(object[] values)
{
this._values = values;
}

public object[] GetValues()
{
return this._values;
}
}

البته ظاهرا این سریالایزر بعضی وقتا موقع دیسریالاز کردن با آرایه مشکل داره ، من از این روش استفاده کردم بعضی وقتا باعث میشه ارتباطم با سرور قطع بشه ، چراشو دیگه فرصت نکردم برم دنبالش

واسه سریال کردن :


System.Runtime.Serialization.Formatters.Binary.Bin aryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.Bin aryFormatter();

formatter.Serialize(socket.GetStream(),message);
socket.GetStream().Flush();

واسه دیسریالایز :


(Message) message = (Message)formatter.Deserialize(socket.GetStream()) ;

C Sharp
سه شنبه 19 مرداد 1389, 08:17 صبح
یه روش دیگه هم هست که یادم رفت بگم ، اونم استفاده از دو کلاس BinaryReader و BinaryWriter هست.

قبلش یه توضیحی بدم : همونطور که خودتون ممکنه متوجه شده باشین ، واسه انتقال اطلاعات توی شبکه ، کلاسهایی مثل Socket,TcpClient,UdpClient اطلاعات رو بصورت استریم Stream (آرایه ای از بایتها) از ما میگیرن و چیزی که توی شبکه انتقال پیدا میکنه همین استریم هست که بسته به ظرفیت شبکه به تکه های کوچکتر تقسیم میشه و هر تکه داخل یک packet
پس در نهایت چیزی که ما تحویل این کلاسها میدیم استریمه ، و این ما هستیم که میگیم چطور اطلاعاتمون به استریم تبدیل بشه و چجوری
این استریم به اطلاعاتی که میخوایم تبدیل بشه

کلاس BinaryWriter تو سازندش یه استریم از ما میگیره ، که ما همون استریم سوکت رو بهش میدیم.
این کلاس متدی به اسم Write داره که میتونه 18 نوع داده ای مختلف رو بگیره و به آرایه ای از بایت تبدیل کنه و روی استریمی که بهش دادیم بریزه

کلاس BinaryReader مثل کلاس قبلی از ما استریمی رو میگیره و 18 متد Read داره که هرکدوم یک نوع داده ای رو از روی استریمی که بهش دادیم میخونه و نوع داده تبدیل میکنه و به ما تحویل میده




int messageType = 10;
string studentCode = "1234567";
BinaryWriter writer = new BinaryWriter(socket.GetStream());

writer.Write(messageType);
writer.Write(studentCode);

socket.GetStream().Flush();






int messageType;
string studentCode ;
BinaryReader reader = new BinaryReader(socket.GetStream());
messageType = reader.ReadInt32();
studentCode = reader.ReadString();