# برنامه نویسی با محصولات مایکروسافت > برنامه نویسی مبتنی بر Microsoft .Net Framework > مقالات مرتبط با Microsoft .Net Framework > مقاله: TCP/IP Socket Programming in Framework.Net 2.0

## __H2__

سلام
در این تاپیک قصد داریم مختصری در خصوص آموزش برنامه نویسی سوکت ها، انحصاراً تحت پروتکل TCP/IP و در دات نت صحبت کنیم.

با توجه به تاپیک
https://barnamenevis.org/showthread.php?t=118051
و نظر دوستان، تصمیم گرفتم یک تاپیک آموزشی مختصر در مورد "برنامه نویسی شبکه تحت پروتکل TCP/IP" بزنم.

انشا ا... کمکی باشد برای دوستان دات نت کار، مخصوصاً C#‎.Net و VB.Net
از کمک دوستان و اساتید موجود در تالار در قنی تر کردن مطالب تاپیک هم استقبال میکنم.

بالاخره، چند نفر، بیشتر میتوانند تایپ و شرح و تفضیل دهند و به جزئیات بپردازند.

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

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

(احتمالاً تاپیک را دو سایت تالار گفتگوی دیگر هم ایجاد میکنم، تا برای اعضا و دوستان دات نت کارم در انجا هم کمکی باشد.)

جمیعاً موفق باشید.

----------


## __H2__

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

تسلط بر سوکت ها خوب است ولی گاهاً نیاز نیست.
اگر برنامه شما از یک بانک اطلاعاتی مثل SQLServer استفاده میکند و میخواهد دیتای واحدی را در رایانه های مختلف شبکه ای محلی یا حتی اینترنت در دو نقطه مختلف کره زمین، استفاده کند، لزومی به برنامه نویسی سوکت نیست.
فقط کافی است با چند کلیک
- برنامه قدرتمند SQLServer را برای شبکه Config کنید.
- برای دیتابیس مورد نظرتان یا کل دیتابیس ها Login و User و Pass تعریف کنید، تا از آنها در رشته های اتصال ConnectionString در برنامه های روی کلاینتها یا حتی روی خود سرور استفاده کنید.

کدهای دات نت شما هم فرقی نمیکند، فقط باید کمی با دقت بیشتر و با ملاحضات همزمانی و اجرا همزمان نوشته شود.

دوستان میتوانند برای اطلاعات بیشتر در خصوص تنظیمات SQLServer به تاپیک های زیر مراجعه کنند.
https://barnamenevis.org/showthread.php?t=118051
https://barnamenevis.org/showthread.php?t=120655
https://barnamenevis.org/showthread.php?t=115957

----------


## __H2__

سلام.
هر رایانه میتواند بیش از یک IP داشته باشد، حداقل چون میتوانید بیش از یک کارت شبکه داشته باشد.
همانطور که خودتان هم میدانید، IP نشانی و آدرس پستی رایانه شما در شبکه است.
که مشخص میکند بسته اطلاعات باید تحویل چه رایانه ای شود.

IP دو نسخه کاربردی دارد.
- آدرسهای ورژن 4 که از اعدادی 32 بیتی استفاده میکرده و در تئوری 2 به توان 32 حالت و رایانه را ساپورت میکند.
در نوشتار این IP چنین تایپ میشود. 217.85.72.32

با گسترش شبکه جهانی اینترنت، کوچکی محدوده فوق دردسر ساز شد و نسخه 6 به وجود آمد.
- آدرسهای ورژن 6 که از اعدادی 128 بیتی استفاده میکند و در تئوری 2 به توان 128 حالت و رایانه را ساپورت میکند. یعنی 2 به توان 96 تا بیش از ورژن 4.
در نوشتار این IP چنین تایپ میشود. fe80::225:96ef:dd26:d582

(مطالب دیگری هم وجود دارد، که با توجه به تمرکز بحث روی سوکت از آنها صرف نظر میکنیم.)

برخی اعداد IP ، انحصاری هستند و معنی خاصی دارند
فقط به عنوان نمونه :

Loopback
IPv4-127.0.0.1 = IPv6-::1
همواره به رایانه جاری اشاره میکنند
 
Broadcast
IPv4-255.255.255.255
آدرسی است که اگر چیزی به آن ارسال شود، همه رایانه ها در شبکه آن دیتا را دریافت میکنند و در نسخه شش دیگر ساپورت نمیشود
 
Widcard
IPv4-0.0.0.0 = IPv6-::
معرف هر آدرس و هر رابطی است
 
و ...


توجه کنید که با توجه به آدرس Loopback حتی رایانه ای که کارت شبکه هم ندارد حداقل یک IP برای خودش دارد.

----------


## __H2__

سلام.
Port را به نوعی میتوان گفت کد پستی برنامه داخل رایانه شما است.
شما در یک لحظه میتوانید در حال چک کردن ایمیلتان در برنامه ای باشید،
میتوانید با IE یک صفحه وب را ببینید
یا به ftp وصل شده باشید
و تازه یک برنامه چت هم باز باشد
و SQLServer هم در گوشه ای کار خودش را کند ... !
(چه شود! آش شبکه ای!)

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

این عدد یک مقدار مثبت 16 بیتی است، یعنی در محدوده رنج ushort ، به بیان دیگر مقداری است بین صفر تا 65535.

اعداد پورت های زیر 1024 برای استانداردهای خاصی رزو شده اند.
مثلاً

21-FTP control
20-FTP data
80-HTTP
443-HTTPS
135-RPC
53-DNS
143-IMAP
993-IMAP SSL
110-POP3
995-POP3 SSL
135-RPC
23-Telnet 
25-SMTP
 
1433-SQLServer 

اگر برایتان نام پورتهای مهم جالب است، سری به این لینک بزنید
http://www.microsoft.com/resources/d....mspx?mfr=true

یا

http://www.iana.org/assignments/port-numbers


این رزو به معنای این نیست که شما نمیتوانید به انها وصل شوید و استفاده کنید، بلکه یک استاندارد جهانی است
همه انتظار دارند یک سوکت سرور روی پورت 80 خدمات HTTP بدهد نه اینکه سیب زمینی بفروشد!

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

----------


## __H2__

سلام
این کلاسس صرفاً یک ظرف است، یک ظرف برای نگه داری IP
همانطور که Integer یک ظرف برای نگه داری اعداد صحیح است.
همانطور که String یه ظرف برای نگه داری متون رشته است.
یعنی هیچ پویا بودنی ندارند، به ذات به هیچ جا وصل نمیشوند.

شما میتوانید هر IP چه ورژن 4 و چه ورژن 6 را در یک کلاسس System.Net.IPAddress جای دهید.
برای پر کردن این کلاسس میتوان از دستورات زیر استفاده کرد که همه با هم برابر هستند و در نهایت موجب تولید یک IPAddress واحد میشوند.

'VB.Net
Dim ip As New System.Net.IPAddress(New Byte(){127, 0, 0, 1})
Dim ip As New System.Net.IPAddress(&H100007FL)
Dim ip As System.Net.IPAddress = System.Net.IPAddress.Parse("127.0.0.1")
 
//C#‎.Net
System.Net.IPAddress ip = new System.Net.IPAddress(new Byte[]{127, 0, 0, 1});
System.Net.IPAddress ip = new System.Net.IPAddress(0x100007FL);
System.Net.IPAddress ip = System.Net.IPAddress.Parse("127.0.0.1");

دستور اول آرایه بایتی میگرد، شامل تک تک بایت های IP .
دستور دوم یک عدد Long میگرید که با اصول ساده باینری و مبنای شانزده میتوان با آن کار کرد.
دستور آخر یک String را سعی میکند به IP تبدیل کند.
یعنی میتوان مقدار یک TextBox را عملاً به متد Parse داد و تبدیل شده اش به IPAddress را تحویل گرفت.
اگر رشته متنی ورودی یک چیز اشتباه و بی ربط و غیر قابل تبدیل به IPAddress باشد یک خطا دریافت خواهید کرد.

اغلب ساختارها و کلاسسهایی که در دات نت که امکان تبدیل از String دارند متد Parse را هم دارند.

'VB.Net
Dim i As Integer = Integer.Parse(StringValue)
 
//C#‎.Net
int i = int.Parse(StringValue);


دیگر اعضای مهم کلاسس IPAddress

- TryParse عمل Parse را به نوعی دیگر انجام میدهد به جای خطا، یک Boolean پس میدهد که نشانه موفقیت/عدم موفقیت در تبدیل است.

- ToString میتوانید از این متد برای تبدیل IP به رشته متنی جهت نمایش و... استفاده کنید.

- Equals مقایسه با یک IPAddress دیگر

- Loopback یک فیلد ثابت است که همواره ادرس IPv4-Loopback را بر میگرداند.

- Broadcast یک فیلد ثابت است که همواره ادرس IPv4-Broadcast را بر میگرداند.

- Any یک فیلد ثابت است که همواره ادرس IPv4-Widcard را بر میگرداند.

- فیلدهای ثابت IPv6XXXXX هم مشابه موارد فوق هستند.

یعنی برای آدرس 127.0.0.1
کد زیر نیز با سه کد درج شده در اول این پست، برابر هستند و هر چهار کد یک نتیجه را در بر دارند.

'VB.Net
Dim ip As System.Net.IPAddress = System.Net.IPAddress.Loopback
 
//C#‎.Net
System.Net.IPAddress ip = System.Net.IPAddress.Loopback;

----------


## __H2__

سلام
این کلاسس هم مثل کلاسس قبلی یعنی IPAddress فقط یک ظرف است.
ظرفی برای نگاه داشتن IP+Port

یعنی عملاً یک IPEndPoint شامل آدرس کامل اتصال به یک سوکت و پورت است. هم عدد IP را دارد و هم عدد Port را.

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

'VB.Net
Dim ip As New System.Net.IPAddress(New Byte(){127, 0, 0, 1})
Dim port As New System.Net.IPEndPoint(ip, 5050)
Dim port As New System.Net.IPEndPoint(&H100007FL, 5050)
Dim port As New System.Net.IPEndPoint(System.Net.IPAddress.Parse("  127.0.0.1"), 5050)
'etc...

//C#‎.Net
System.Net.IPAddress ip = new System.Net.IPAddress(new Byte[]{127, 0, 0, 1});
System.Net.IPEndPoint port = new System.Net.IPEndPoint(ip, 5050);
System.Net.IPEndPoint port = new System.Net.IPEndPoint(0x100007FL, 5050);
System.Net.IPEndPoint port = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("  127.0.0.1"), 5050);
//etc...


بعد از نمونه سازی با دستور new اگر خودمان هم به IPAddress و Port نگه داری شده در آن نیاز داشتیم، این کلاسس دو Property با نام Address و Port و به همین منظور دارد که به ترتیب مقدار IPAddress و Port را بازمیگردانند.

----------


## __H2__

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

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

TCP/IP یکی از پروتکل های تحت شبکه و کار با سوکت ها است.
این پروتکل اتصال گرا است و اطمینان از دست نرفتن اطلاعات در آن زیاد است و یک تضمین هایی روی اتصال ایمن و رسیدن و تکرار بسته ها در صورت خطا هم دارد و پروتکل استاندارد وب هم شده.

شاید بتوان TCP را معروف ترین و پرکاربرد ترین پروتکل به حساب آورد.

=====

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

----------


## __H2__

سلام مجدد
...(ادامه پست قبل که جا نشد!)

برای ساخت یک نمونه Socket جدید نیاز به سه پارامتر داریم:

1) System.Net.Sockets.AddressFamily
2) System.Net.Sockets.SocketType
3) System.Net.Sockets.ProtocolType


1)
-پارامتر اول ساختار و نوع IP را مشخص میکنید که پرکاربرد ترین گزینه ها InterNetwork برای IPv4 و InterNetworkV6 برای IPv6 است.
کلاسس IPAddress هم یک ReadOnly Property با نام AddressFamily دارد، که میتوان از این مقدار برای این پارامتر اول ساخت Socket هم استفاده کرد.

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

3)
-پارامتر سوم و اخر هم پروتکل کاری را ست میکند، یک لایه استاندارد بالاتر.
پرکاربرترین گزینه ها هم Tcp و Udp هستند، که برای بحث ما فقط Tcp باید انتخواب شود.

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

'VB.Net
Dim ip As System.Net.IPAddress = System.Net.IPAddress.Parse("127.0.0.1")
Dim point As New System.Net.IPEndPoint(ip, 80)
 
Dim socket As New System.Net.Sockets.Socket(System.Net.Sockets.Addre  ssFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)
Dim socket As New System.Net.Sockets.Socket(ip.AddressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)
Dim socket As New System.Net.Sockets.Socket(point.AddressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)
 

//C#‎.Net
System.Net.IPAddress ip = System.Net.IPAddress.Parse("127.0.0.1");
System.Net.IPEndPoint point = new System.Net.IPEndPoint(ip, 80);
 
System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(System.Net.Sockets.Addre  ssFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)
System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(ip.AddressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)
System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(point.AddressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)

----------


## __H2__

سلام
مرحله بعد از ساخت سوکت، اتصال سوکت است
برای این امر دو متد Bind و Connect وجود دارد که هر دو یک IPEndPoint میگیرند.
(انشاا... لازم نیست یاد اوری کنم مطالب با محوریت پروتکل TCP بیان میشوند.)

متد Bind به سیستم عامل اعلام میکند که شما را به پورت خاصی وصل کند.
این متد را برای سوکت های سرور استفاده میکنیم تا به سیستم عامل اعلام کنیم تمام درخواست های رسیده به یک آدرس و پورت خاص را به سوکت و برنامه ما تحویل دهد.

متد Connect شما را برای گرفتن خدمات به آدرس و پورت خاصی وصل میکند.
این متد را فقط برای سوکت های سمت کلاینت استفاده میکنیم تا سیستم عامل ما را به سوکت سرور برای خدمات گیری وصل کند.
این متد در زیر ساز داخلی سیستم عامل کار Bind را هم انجام میدهد و اصولاً نیاز به Bind را بر طرف میکند.

به صورت ساده میتوان این طور گفت که Bind متد اتصال برای سوکت سرور است و Connect متد اتصال برای سوکت کلاینت.
هر دو این متدها به دلایل مختلف میتوانند به خطا مواجه شوند مثلاً
در سرور شاید یک سوکت دیگری پورت را قبلاً گرفته باشد
و یا در کلاینت شاید سوکنت نظیر سرور فعال نباشد یا ایرادی در ارتباط شبکه باشد 
و...

ضمناً تنظیم خصوصیت ExclusiveAddressUse قبل از Bind معمولاً در سوکت های سمت سرور مشخص میکند که باید پورت انحصاراً در اختیار سوکت ما باشد یا نه.

(کد خاصی ندارد، کافیست نمونه IPEndPoint را تحویل متد بدهید.)

=====

_قابل توجه کاربر jas1387 که جواب آخرین سوالاتشان در تاپیک قبلی به این تاپیک محول شده بود._

----------


## __H2__

سلام
پس از تمام ارسال ها و دریافت ها، در نهایت برای قطع ارتباط یک سوکت میتوان از دستورات Close و Dispose و Shutdown استفاده کرد.
در خصوص شی سوکت دستور Close و Dispose عملکرد یکسانی دارند و سوکت را کاملاً بسته و به نوعی نابود میکند و منابع سیستم عامل را آزاد میکنند.

اما دستور Shutdown یک پارامتر از نوع System.Net.Sockets.SocketShutdown میگیرد و میتواند خط ارسال و دریافت را جداگانه ببندد.
پیغامی که در عوض بسته شدن سوکت در یک سر به سوکت نظیر در آن سر میرسد، دریافت اطلاعات جدید با طول صفر بایت است.
هنوز دستور دریافت اطلاعات را نگفته ایم ولی فعلاً بدانید که اگر اطلاعاتی با تعداد بایت صفر، دریافت شود، یعنی سوکت نظیر در آن سمت، دیگر وجود ندارد و قائدتاً باید در این سمت هم درصورت نیاز منابع سیستم را آزاد کنیم.

در برخی برنامه ها که بسته شدن کامل و امن هر دو سوکت برایشان خیلی مهم است، اول Shutdown را با Send اجرا میکنند و بعد هم منتظر رسیدن پیغام نظیر از سوکت سمت دیگر میشوند و بعد سوکت را کامل میبندند.
ولی اکثراً یک Close ساده، کافی است.

سه دستور زیر تقریباً یک نتیجه دارند:

'VB.Net
*socket.Close()*
DirectCast(socket, System.IDisposable).Dispose()
socket.Shutdown(System.Net.Sockets.SocketShutdown.  Both)


//C#‎.Net
*socket.Close();*
((System.IDisposable)socket).Dispose();
socket.Shutdown(System.Net.Sockets.SocketShutdown.  Both);

----------


## __H2__

سلام
سوکت کلاینت به محض اجرای دستور Connect آماده ارسال و دریافت اطلاعات است ولی در سرور عملاً باید دستورات Listen و Accept نیز اجرا شوند.

متد Listen سرور را برای پذیرفتن درخواستهای کلاینتها به یک تعداد صف خاص آماده میکند، معمولاً آن را با حداکثر مقدار ممکن فراخانی میکنند تا در آینده و با کوچک و بزرگ شدن شبکه و توسعه و ... همواره کد صحیح کار کند ،ولی مقداردهی یک عدد منطقی و مورد انتظار شاید بد نباشد و مثلاً میتواند یک نیمچه سدی در مقابل حملات DOS باشد.

سه دستور زیر دقیقاً یک کد IL تولید میکنند.

'VB.Net
'socket = New ...
'socket.Bind (...

socket.Listen(Integer.MaxValue)
socket.Listen(&H7FFFFFFF)
socket.Listen(2147483647)


//C#‎.Net
//socket = new ...
//socket.Bind (...
 
socket.Listen(int.MaxValue);
socket.Listen0x7FFFFFFF);
socket.Listen(2147483647);

----------


## __H2__

سلام مجدد
به قول قدیمی ها، سلام سلامتی می آره!

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

ولی در سرور خیلی جزئی اوضاع فرق میکند و سرور باید یک خط ارتباطی با هر یک از کلاینت ها به طور مجزا داشته باشد، در نتیجه همان یک نمونه سوکتی که اول در سرور میسازیم کفایت نمیکند و ما نیاز به یک خط ویژه ارتباطی با هر کلاینت داریم.
برای آنکه بهتر متوجه شوید، مرکز تلفن 118 را در نظر بگیرید، در ظاهر فقط یک تلفن 118 وجود دارد و این خیلی بدیهی است که از هر جایی کافی است فقط 118 را بگیریم، این لفظ کلی تلفن 118، مثل همان شی سوکت اصلی سرور میماند که در خودمان سرور با New آن را میسازیم.
ولی بعد هر کس با 118 تماس میگیرد برای به یک اپراتور مجزا و یک گوش تلفن مجزا وصل میشود، شماره تماس همه  گوش های تلفن مرکز، همان 118 است ولی مثل تماس گیرنده، اینجا یک گوشی وجود ندارد و کفایت نمیکند، اگر یک گوشی در 118 باشد، طبیعی است که همه صحبتهای تماس گیرنده و همه جوابهای مرکز قاطی میشوند.

متد Accept مسئول برداشتن گوشی جدید در سرور و ایجاد یک خط ارتباطی مستقل است.

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


دستور زیر آنقدر صبر میکند تا فقط یک کلاینت در خواست اتصال بدهد، انگاه اتصال را پذیرفته و یک پیغام متنی Hello برای کلاینت ارسال میکند و اتصال را پایان میدهد و میبندد و همه چیز تمام میشود !
(دستور Send را توضیح خواهیم داد، فعلاً بدانید که وظیفه ارسال اطلاعات را به عهده دارد.)

'VB.Net
'socket = New ...
'socket.Bind ( ...
'socket.Listen ( ...

Dim msgbuffer() As Byte = System.Text.Encoding.UTF8.GetBytes("Hello")

Dim clientsocket As System.Net.Sockets.Socket = socket.Accept()
clientsocket.Send(msgbuffer)
clientsocket.Close()


//C#‎.Net
//socket = new ...
//socket.Bind ( ...
//socket.Listen ( ...

byte[] msgbuffer = System.Text.Encoding.UTF8.GetBytes("Hello");

System.Net.Sockets.Socket clientsocket = socket.Accept();
clientsocket.Send(msgbuffer);
clientsocket.Close();


برای یک برنامه واقعی باید Accept را در یک حلقه تکرار کرد تا تمام درخواستهای همه کلاینتها پردازش شود.
مثلاً کد زیر هر درخواستی را که برسد قبول میکند و یک پیغام Hello به ان ارسال میکند و مکالمه را پایان میدهد و مجدداً منتظر درخواست بعدی میشود.

'VB.Net
'socket = New ...
'socket.Bind ( ...
'socket.Listen( ...

Dim msgbuffer() As Byte = System.Text.Encoding.UTF8.GetBytes("Hello")

Do
     Dim clientsocket As System.Net.Sockets.Socket = socket.Accept()
     clientsocket.Send(msgbuffer)
     clientsocket.Close()
Loop


//C#‎.Net
//socket = new ...
//socket.Bind ( ...
//socket.Listen ( ...

byte[] msgbuffer = System.Text.Encoding.UTF8.GetBytes("Hello");

while (true)
{
     System.Net.Sockets.Socket clientsocket = socket.Accept();
     clientsocket.Send(msgbuffer);
     clientsocket.Close();
}

----------


## __H2__

سلام

Serialize Deserialize
=====
برای ارسال و دریافت اطلاعات، تنها فرمت مورد قبول در سطح سوکت، اطلاعات باینری خالص است، آرایه بایتی.
وظیفه کد ما است که آیتم مورد نظر برای ارسال را Serialize به آرایه بایتی کند و پس از دریافت هم Deserialize کردن به دیتا بر عهده کد ما است.

- برای این تبدیلات دیتاهای معمول مثل Integer و Double و... میتوان از کلاسهای System.IO.BinaryReader و System.IO.BinaryWriter استفاده کرد.

- برای تبدیلات String هم میتوان از System.Text.Encoding.UTF8 استفاده کرد.

- برای تبدیلات Image هم میتوان از کلاسس System.IO.MemoryStream و متدهای FromStream و Save استفاده کرد.

- برای اشیای پیچیده و ترکیبی که تبدیلات آنها مشکل است میتوان از System.Runtime.Serialization.Formatters.Binary.Bin  aryFormatter استفاده کرد ولی این تبدیلات از تبدیلات مشابه فوق الذکر کندتر و حجیم تر هستند.

و...

Send
=====
این متد جهت ارسال اطلاعات استفاده میشود و چندین Overload دارد، یکی از کاملترین Overload های این متد چهار پارامتر میگیرد.

buffer() As Byte
offset As Integer
size As Integer
socketFlags As System.Net.Sockets.SocketFlags

-پارامتر اول خود آرایه بایتی است که باید ارسال شود.
-پارامتر دوم ایندکس آیتم شروع در آرایه است که معمولاً عدد صفر است.
-پارامتر سوم تعداد بایتهایی است که از محل مشخص شده باید ارسال شوند.
-پارامتر آخر فلاگهای مشخصه ارسال است که ما گزینه None را انتخاب میکنیم.

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

buffer() As Byte
size As Integer
socketFlags As System.Net.Sockets.SocketFlags

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

- پارامتر دوم، اندازه ای از آرایه ای است که متد مذکور اجازه دارد از آن استفاده کند.

- پارامتر آخر هم همانطور که گفتیم فلاگ های خاص نحوه دریافت و ارسال است که ما از گزینه None استفاده خواهیم کرد.


اگر آرایه ای 10K بایتی ما بدهیم، لزومی به صبر برای پر شدن کل آرایه نیست و یک بسته 1 بایتی اطلاعات هم برسد، کافیست تا متد انجام شده و به انتها برسد.
اگر بلوک بسته ای اطلاعات رسیده شده، بیشتر از حجم بافر ما باشد، تا حدی که بافرما اجازه دهد اطلاعات را دریافت میکنیم و مابقی را در اجرای بعدی Receive دریافت خواهیم کرد.

کد خاصی هم که فعلاً ارزش نوشتن داشته باشد، ندارد!

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

----------


## __H2__

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

requestCallback As System.AsyncCallback
state As Object

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

روال پایانی که در انتهای انجام عمل ناهمزمان اجرا میشود و باید اشاره گر آن به پارامتر requestCallback داده شود دارای امضا و فرمت زیر است.

'VB.Net
Sub MethodName (ByVal ar As System.IAsyncResult)

//C#‎.Net
void MethodName (System.IAsyncResult ar)

ar که به ما تحویل داده میشود مشخص کنند مواردی از جمله موفقت و اتمام صحیح عملیات و همان پارامتر state هم است (البته با نام AsyncState)
برای اتمام کلی فرایند و چرخه اجرا، این پارامتر ar باید به EndXXXXX پاس داده شود و اگر عملیات مقدار بازگشتی هم داشته باشد EndXXXXX ان را به ما میدهد.

به مثال فرضی زیر دقت کنید.

'VB.Net
'Synchronous
Dim ret As TypeName = ClassVariantName.FunctionName(125)
'...
'=====
'VB.Net
'Asynchronous
ClassVariantName.BeginFunctionName(125, AddressOf MethodName, "Mahdi")


Private Sub MethodName (ByVal ar As System.IAsyncResult)
	' "Mahdi" === ar.AsyncState
	Dim ret As TypeName = ClassVariantName.EndFunctionName(ar)
	'...
End Sub




//C#‎.Net
//Synchronous
TypeName ret = ClassVariantName.FunctionName(125);
//...
//=====
//C#‎.Net
///Asynchronous
ClassVariantName.BeginFunctionName(125, new System.AsyncCallback(MethodName), "Mahdi");


private void MethodName (System.IAsyncResult ar)
{
	// "Mahdi" === ar.AsyncState;
	TypeName ret = ClassVariantName.EndFunctionName(ar);
	//...
}


فراموش نکنید مزیت روش غیر همزمان آن است که ریسمان شما بلوکه نمیشود و شما میتوانید به کارهای  دیگر برسید و هر موقع عملیات تکمیل شد، روال پایانی اجرا میشود و مقدار بازگشتی را هم تحویل میگیرید.
مطالب فوق را قابل تعمیم بیان کردم و عیناً میتوانید برای هر کلاسسی در دات نت که جفت روال BeginXXXXX و EndXXXXX را دارد اجرا کنید، از جمله:
BeginConnect و BeginAccept و BeginSend و BeginReceive و...
کافی است تست کنید.

----------


## __H2__

سلام
حقیقتش نمیخواستم این توضیح را اضافه کنم ولی گفتم بحث را یک کم کاملتر کنم....
=====
اغلب مواقع، در کدها و برنامه ها به جای آنکه IP را مستقیم از کاربر بگیریم از نام استفاده میکنیم.
یک رایانه یا سرور در شبکه میتوانید نام هم داشته باشد و همانطور که قبلاً هم گفتیم، هر رایانه میتواند چندین IP داشته باشد.

کلاسس Dns وظیفه ترجمه نام به IP را بر عهده دارد، یعنی ما وقتی به شبکه وصل هستیم نام یک رایانه در شبکه را میدهیم و IP هایش را تحویل میگیریم.
مثلاً اگر به شبکه اینترنت وصل باشیم میتوانیم نام www.microsoft.com را بدهیم و IP هایش را به دست آوریم.

با این کلاسس و کمی کد اضافه برنامه میتواند علاوه بر IP با نام هم تغذیه شود و کار کند و خودش خودکار از نام به IP برسد.

مثلاً کد زیر سعی میکند به همه IP های متناظر یک نام وصل شود و به اولین IP که کار کرد وصل شود و جستجو را تمام کند.

'VB.Net
Dim port As Integer = 80
Dim socket As System.Net.Sockets.Socket = Nothing
 
For Each ip As System.Net.IPAddress In System.Net.Dns.GetHostEntry("www.microsoft.com").A  ddressList
    Try
        socket = _
            New System.Net.Sockets.Socket( _
            ip.AddressFamily, _
            System.Net.Sockets.SocketType.Stream, _
            System.Net.Sockets.ProtocolType.Tcp)
 
        socket.Connect(New System.Net.IPEndPoint(ip, port))
 
        Exit For
    Catch
        socket = Nothing
    End Try
Next
 
If (socket IsNot Nothing) Then
    '...
    '...
    socket.Close()
End If
 
 
 
//C#‎.Net
int port = 80;
System.Net.Sockets.Socket socket = null;
 
foreach(System.Net.IPAddress ip in System.Net.Dns.GetHostEntry("www.microsoft.com").A  ddressList)
{
    try
    {
        socket = 
            new System.Net.Sockets.Socket(
            ip.AddressFamily,
            System.Net.Sockets.SocketType.Stream,
            System.Net.Sockets.ProtocolType.Tcp);
 
        socket.Connect(new System.Net.IPEndPoint(ip, port));
        break;
    }
    catch
    {
        socket = null;
    }
}
 
 
if (socket != null)
{
    //...
    //...
    socket.Close();
}


خود دوستان میتوانند هر کجا خواستند، IP را به طریقه فوق به دست اورند.

----------


## __H2__

سلام مجدد
با توجه به هدف تاپیک ...



> سعی میکنیم، تا توضیح ساخت یک برنامه فوق العاده، فوق العاده ساده چت پیش برویم


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

*در نتیجه قائدتاً از این تاپیک فقط میماند نمونه کد نهایی.*
که باید انشا ا... وقت کنم و بنویسم.
در کد نهایی، در ضمینه سوکت و شبکه از متدی غیر از متدهای ذکر شده در تاپیک استفاده نخواهم کرد ولی استفاده از کلاسس های عادی و مرسوم غیر شبکه ای طبیعی است.

موفق و پیروز و سربلند باشید.

----------


## __H2__

سلام
میبخشید کار داشتم و تهیه کد کمی طول کشید...

یک نمونه الکی قبلاً داشتم که نمونه جدید و اصولی تر را روی همان اپلود کردم
RightClick->Save Target As
http://www.h02.ir/Download.aspx?File...SocketChat.zip

نمونه فوق فوق العاده ساده است و
متن پیغام کلاینت ها فقط در سرور نمایش داده میشود (کد اضافه تری ندارد) و 
متن پیغام سرو در یک حلقه for each برای همه کلاینت ها ارسال میشود.
فقط همین!

اول باید تک نمونه با دکمه رادیویی سرور اجرا شود و بعد میتوانید به تعداد دلخواه مجدداً فایل را اجرا کنید و دکمه رادیویی را روی کلاینت قرار دهید. (یک سرور و بی نهایت کلاینت.)

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

(البته کد فوق قابل بهینه شدن و بهتر نوشته شدن است، ولی ترسیدم کمی پیچیده شود و از سادگی اش کاسته شود.)

اهداف تاپیک تامین شده و من هم قول نمیدهم ولی اگر وقت کنم، شاید انشا ا... نمونه یکم کاملتری از کد فوق هم تهیه کنم تا اعمال پیچیده تری مثل پیغام Private و Public و لیست افراد و... را هم داشته باشد. (ولی این اعمال دیگر مشکل TCP socket ها نیست و باید الگوریتم متان را اصلاح کنید.)

البته انشا ا... مطالب تاپیک را در قالب pdf هم به همین پک دانلود اضافه خواهم کرد.

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

جمیعاً موفق و پیروز و سربلند باشید.

----------


## Armin060

برنامه اجرا نميشه...ميشه فايل exe رو بزاری؟

----------


## __H2__

سلام



> برنامه اجرا نميشه...ميشه فايل exe رو بزاری؟


سورس با VS2008 نوشته شده و خودم با تغییراتی در vbproj و csproj سعی کرده ام تا در VS2005 هم باز شود.

من مجدداً تغییرات جدیدی در این فایلها برای هماهنگی با VS2005 دادم ولی چون VS2005 را نصب ندارم نمیتوانم چک کنم و از صحت کار مطمئن شوم.
پیشنهاد میکنم مجدداً دانلود کنید و تستی انجام دهید و اگر در VS2005 هم باز شد که هیچ...
وگرنه چون کدها تفاوت ذاتی در VS2005 و VS2008 ندارند، شما میتوانید خودتان در VS2005 فرمان newproject بدهید و از فایل کدهای vb و cs در پروژه خود استفاده کنید.

این هم نسخه exe کامپایل شده vb و #c که در واقع یکی هستند:

----------


## Armin060

مرسی...ولی من تمامی فايل ها رو در يك پروژه جديد اضافه كردم....اما باز خطا داد....مال منم Vs2008 هست.
راستی ميشه بگيد چطوری ميشه از سرور فقط به يك كلاينت پيام ارسال كرد. همون private. يه سورس دارم ولی از اين نحوه استفاده نميكنه ( TCP/IP ).

----------


## __H2__

سلام



> مرسی...ولی من تمامی فايل ها رو در يك پروژه جديد اضافه كردم....اما باز خطا داد....مال منم Vs2008 هست.


یعنی شما با VS2008 موفق به باز کردن پروژه ها نشدید!!!!!!!
(البته من از VS2008-SP1 استفاده میکنم، شاید در نسخه اولیه VS2008 پروژه باز نشود، نمیدانم!)
میتوانید متن پیغام خطا یا تصویر و ... را بدهید؟





> راستی ميشه بگيد چطوری ميشه از سرور فقط به يك كلاينت پيام ارسال كرد. همون private. يه سورس دارم ولی از اين نحوه استفاده نميكنه ( TCP/IP ).


اگر انشا ا... بتوانید کدها را در VS ببنید، خواهید دید که در کد Send مربوط به سرور یک حلقه For قرار دارد که ارسال را برای تمام کلاینت ها انجام میدهد، کافی است حلقه For را بردارید و ارسال را فقط به کلاینت مورد نظر انجام دهید.

----------


## Armin060

مرسی. با كلی تلاش برنامه رو كامپايل كردم و درست كار كرد....

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

----------


## __H2__

سلام



> اگر بخواهيم از يك كلاينت نوشته رو برای همه ی كلاينت ها بفرستيم بايد نوشته رو بفرستيم به سرور و بعد سرور برای تمام كلاينت ها بفرستد


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

در اصل خیلی بهتر است پیغام شما به جای یک String ساده یک class یا struct باشد مثلاً با اعضای زیر:
ID_Sender-Int32
ID_Receiver-Int32
ID_MessageType-Byte
(EndHeader-9Byte)
MessageBody-Object

در واقع بسته های پیغام را شامل یک header دلخواه کنید و کمی قانونمند تر کنید.

در مورد سوال شما، مثلاً میتوان وقتی ID_Receiver عدد صفر یا 1- باشد منظور این باشد که باید در یک حلقه for برای همه ارسال شود.
حتی در مکانیزم پیشرفته تر میتوان نوع ID_Receiver را یک آرایه گذاشت تا بتوان به تعداد خاصی از افراد مشخص هم پیغام را ارسال کرد.


ID_MessageType هم وظیفه جداسازی پیغام هایی با نوع مختلف را دارد.
مثلاً بسته ارسالی شما میتواند یک متن باشد یا یک تک تصویر یا یک فریم از یک فیلم برداری دنباله دارد و یا در یک برنامه مدیریتی کافی نت میتوانید بسته برای کاربر انسانی نباشد و حاوی دستورات سیستمی مثل reset و shutdown و... باشد که مدیر کافی نت بتواند روی کلاینت ها اعمال کند.
(
البته در مبنای باز پیچیده تر میتوان به جای ID_MessageType از وراثت و ماژول های سریالی کننده خودکار دات نت هم استفاده کرد، ولی این کار حجم اطلاعات را کمی افزایش میدهد.
)

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

----------


## Armin060

علی، من اين برنامه رو تو Lan تست كردم، خطا ميداد. يعنی سرور رو روی يه كامپيوتر و كلاينت رو روی چند تا كامپيوتر ديگه اجرا كردم، ولی موقع وسل شدن خطا ميده. چه كار كنم؟

----------


## __H2__

سلام
ایا ip سرور را اصلاح کردید؟
شما باید ip رایانه سرور را دقیق به دست اورید (مثلاً توسط ipconfig و ابزار مشابه و...) و مقدار مناسب را به برنامه تحویل دهید.

127.0.01 فقط به رایانه جاری اشاره میکند مثل \. در مسیرهای هارد

----------


## sepehr.net

واقعا دستت درد نکنه خیلی خیلی خوب بود. 
اگه در تکمیل مطالب بالا کلاس های TcpListener,TcpClient,UdpClient رو توضیح بدی خیلی عالی میشه .

----------


## __H2__

سلام



> اگه در تکمیل مطالب بالا کلاس های TcpListener,TcpClient,UdpClient رو توضیح بدی خیلی عالی میشه .


حقیقتش ارزش خاصی ندارند!!!
همانطور که دیدید ما به راحتی و با دسترسی مستقیم به سوکت تنوانستیم اطلاعات را مبادله کنیم و نه برای کلاینت ها نیازی به TcpClient پیدا کردیم و نه برای سرور TcpListener نیاز شد.

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

=====

UdpClient هم که کلاً UDP است و اصلاً خیلی از مطالب تاپیک که در خصوص TCP است در این مورد صادق نیست و میتوان گفت UDP خودش تاپیکی جدا در همین حد شاید نیاز داشته باشد.
که در این مورد هم باز خود سوکت امکانات اصلی UDP را دارد و همچنان برای کسی که تسلط کافی به متدها و خواص کلاسس Socket داشته باشد، مورد فوق نیاز نخواهد شد.

=====

موفق باشید.

----------


## sepehr.net

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

----------


## nariman_t

با سلام به همه بچه ها آقا یه سوال کلی که راحت شیم کتابی سراغ ندارید که مرجع و کامل Soket programing رو تحت vb.net آموزش داده باشه pdf چیزی هم سراغ دارید بگید کتابشم باشه مشکلی نیست

----------


## __H2__

سلام



> با سلام به همه بچه ها آقا یه سوال کلی که راحت شیم کتابی سراغ ندارید که مرجع و کامل Soket programing رو تحت vb.net آموزش داده باشه pdf چیزی هم سراغ دارید بگید کتابشم باشه مشکلی نیست


PDF انگلیسی اگر سرچ کنید پیدا خواهید کرد.
اگر اشتباه نکنم یک کتاب قدیمی (2003) فارسی هم یکی از ناشران برای "برنامه نویسی شبکه در دات نت" چاپ کرده است.

میتوانید از برنامه نصبی MSDN و یا MSDN-Online هم استفاده کنید.

----------


## mehdi_7

خیلی ممنون
اگر امکان داره، مطالب رو تکمیل کن
لیست کاربران متصل به سرور و ارسال پیام خصوصی رو هم توضیح بدید لطفا

----------


## __H2__

سلام



> لیست کاربران متصل به سرور و ارسال پیام خصوصی رو هم توضیح بدید


با شرمندگی بسیار گمان نکنم فرصت کنم.  :خجالت: 
یک تاپیک XNA آموزشی زدم، توش ماندم! (از نظر تایپ و نوشتن مطلب و به روز رسانی)

در pdf اصل طریقه انتقال اطلاعات بیان شده و میتوان با خواندن ان دو رایانه را به هم متصل کرد.
بقیه اش میشود الگوریتم که بیایید و اطلاعات را مدون شده منتقل و مدیریت کنید.

موفق باشید.

----------


## ferferi

سلام دوست من
من در حال تکمیل یک پروژه هستم و این روش شما رو پیاده سازی کردم
در یک قسمتهایی به مشکل برخورد کردم
یک نمونه برنامه درست کردم تا دید بهتری پیدا کنم
من برای ارسال به سرور مشکلی ندارم ولی برای ارسال به کلاینت مشکل دارم
برنامه رو اینجا میذارم تا ببینیش و اشکال من رو درست کنی
مرسی بابت مقاله ای که نوشته بودی و بسیار کاربردی هستش

----------


## ferferi

الان برنامه رو ساده تر کردم
کسی میتونه این سیستم رو درست کنه؟
اگه کسی تونست فوری بگه، تا جایی که بتونم جبران میکنم

توضیح:
یک سیستم هستش که هم به عنوان سرور و هم به عنوان کلاینت کار میکنه (یعنی باید کار کنه)
کار نمیکنه!

----------


## __H2__

سلام



> یعنی باید کار کنه


!!!!!!!!!!!!!!!!




> یک سیستم هستش که هم به عنوان سرور و هم به عنوان کلاینت کار میکنه (یعنی باید کار کنه)
> کار نمیکنه!


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

1)
سوکت سرور را بجای IPAddress.Any روی همان IP که برای کلاینت هم تنظیم کردید، تنظیم کنید. (127.0.0.1)

2)
در متد OnReceive_s متغییر محلی با نام clientSocket تعریف شده در حالیکه در این نقطه باید متغیر سطح کلاس clientSocket پر میشده.
با این عمل متغیر سطح کلاس clientSocket همچنان null و غیر معتبر باقی میماند.

3)
متد OnSend_s با متغییر clientSocket در سطح کلاس فراخوانی میشود ولی داخل این متد از serverSocket استفاده کرده اید.

4)
در متد OnReceive_s به جای ارسال اطلاعات باید مجدد BeginReceive را فراخوانی میکردید، تا بلوک بعدی اطلاعات هم دریافت شود.
اینطوری فقط اولین پیام دریافت میشود.

5)
در متد OnReceive_s
 خیلی راحت از یک TextBox روی فرم استفاده کردید!
در حالیکه این متد در ریسمان دیگری اجرا میشود و TextBox با ریسمان اصلی برنامه ساخته شده.
این کار مستعد خطای ریسمان های متقاطع است.
برای دسترسی به اجرای روی فرم باید از متدهای Invoke و BeginInvoke استفاده کنید.

=====

6)
سوکت های متصل شده شما، به طرز صحیح و مناسب بسته و حذف نمیشوند و فقط تمرکز کدها روی ارتباط بوده، دیگر قطع ارتباط ... !

پیشنهاد میکنم به سمپل ارائه شده دقت بیشتری کنید.
موفق باشید.

----------


## ferferi

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

----------


## __H2__

سلام



> من دستورات ساده را میخواهم


میدانید، چند نفر در همین سایت و یک سایت دیگر، تماس گرفته بودند و میخواستند چیز کامل تر و جامع تری قراری دهم و به نوعی گفته بودند این سمپل خیلی ساده است؟!




> مثال زیر رو تکمیل کنید


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

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

=====

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

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

----------


## sajjad2

برنامه ی بسیار مفیدی بود . می شه . کمی تکمیلش کنید . تعدادی کامنت هم اینجا و آنجای کد اضافه کنید . 
اگه می شه امکان ارسال فایل رو به عنوان مثال اضافه کنید . 
در مورد beginxxxx هم بیشتر توضیح بدید . نخ در بخش کلاینت هیچ وقت endxxx نمی شه . من از msdn فهمیدم که باید end رو توی callback استفاده کرد اما نتونستم مطلب رو درک کنم . مهم xxxxxx
در مورد طریقه ی ارسال دستورات تلنت برای سخت افزار هم اگه می شه توضیح بدید . باید دستورات رو به صورت تکست بنویسم بعد کد کنم ؟ ؟؟؟خیلی مهم xxxxxx
----------
من اینها رو از نرم افزار شما فهمیدم . 
شما اول لایه ای به نام ichat  ایجاد کردید رویدادهای IDisposable رو به اون نسبت دادید و دو تا پروپرتی به اون اضافه کردید . بعد از اون دو تا کلاس کلاینت و سرور رو با اون ایجاد کردید . 
؟؟؟/ چرا آپشن رو استریکت گذاشتید ؟ مگه کامپیر چش بود . 
؟؟؟؟؟؟ Public Sub New()

    End Sub 
این به چه کاری می یاد ؟ 
بقیه اش برای فردا

----------


## sajjad2

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

----------


## sajjad2

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

----------


## __H2__

سلام



> من احتیاج دارم که تعدادی دستور رو چند ثانیه یک بار برای یک سخت افزار بفرستم


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

==============

اگر منظورتان اتصال تجهیزات دیجیتالی خارجی به پورت های واقعی سخت افزاری رایانه است، این تاپیک اصلاً ارتباطی به مشکل شما ندارد و کمکی نخواهد کرد.
در دات نت کلاس ارتباط با درگاه COM را داریم.(System.IO.Ports.SerialPort)
برای اتصال به درگاه LPT هم میتوانید به مقاله زیر مراجعه کنید:
http://support.h02.ir/fwlink/?LinkId=1000292003





> من با ایننرم افزار و کمی دستکاری به پورت میل متصل شدم


(اگر هم منظورتان همان مفهوم پورت نرم افزاری در شبکه ها و TCP/IP و... است لطفاً توضیح بیشتری ارائه دهید.)

منظورتان از "پورت میل" چیست؟ منظورتان همان e-mail تحت پروتکل SMTP است؟
پروتکل SMTP یک پروتکل پیشرفته با مستندات زیاد است.
دات نت به صورت داخلی دارای کلاس و امکانات ویژه ای برای ارسال ایمیل تحت پروتکل SMTP و TCP/IP است و شما نیازی به اتصال مستقیم سوکتی با سرور SMTP ندارید.
(System.Net.Mail.SmtpClient)

موفق باشید.

----------


## sajjad2

سلام و ممنون بابت کد خیلی عالی تون 
خب من توی کامند پرومت مینویسیم . telnet mail.site.com 25  با این دستور کانتکت می شه و می تونم با دستورات بعدی برای اون میل بفرستم .   روی سایت خودتون امتحان کنید . البته این نرم افزار من قراره کدهای مشابهی رو روی تلنت پورت 23 برای دستگاهی بفرسته و جواب بگیره . سخت افزار کاملا به تلنت جواب می ده . یعنی همه ی command ها از طریق تلنت و cmd به دستگاه منتقل می شن . که خیلی وقت گیره . من می خوام با فشار دگمه ای دستور توسط نرم افزار فرستاده بشه .
الان به عنوان مثال من در نرم افزار شما در حالت کلاینت  پرت رو به 25 تغییر دادم بعد به آی پی سرور میل متصل شدم و جواب تایید اتصال رو گرفتم اما با دستورات بعدی هیچ جوابی نرسید . روی حالت سرور هم که قرارش می دم . با وارد کردن آی پی ارور می ده . می گه ipendpoint  معتبر نیست . 
من با این شکل برنامه نویسی شما آشنا نیستم مخصوصا با نخ ها کار نکردم . اگه مراحل کار رو توضیح بدید . ممنون می شم . خودم به کد ور می رم درستش می کنم . 
ببخشید اگه نمی تونم منظورم رودرست برسونم .

----------


## __H2__

سلام



> سخت افزار کاملا به تلنت جواب می ده...


همین عبارت ساده، مطلب را شفاف میکند.




> روی حالت سرور هم که قرارش می دم . با وارد کردن آی پی ارور می ده . می گه ipendpoint معتبر نیست.


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




> اما با دستورات بعدی هیچ جوابی نرسید


من الآن دقیقاً حضور ذهن ندارم چه کدی نوشته بودم ولی مطمئن هستم که از کدینگ UTF8 استفاده کردم، در حالیکه احتمال کارکردن سوکت سروری شما با کدینگ ASCII بسیار محتمل است و این میتواند منشاء ای برای مشکل و عدم هماهنگی باشد و مطلب بعد هم انکه در خیلی از این پروتکلها خود کاراکتر خط جدید یا همان Enter (دو کاراکتر 10-13 یا تک کاراکتر 13) هم در پایان پیام ها مهم است.

دو مورد فوق را در کد قبلی اصلاح کنید و مجدد آزمایش کنید.




> اگه مراحل کار رو توضیح بدید . ممنون می شم


خوب مگر در کل این تاپیک و pdf نهایی ان کاری غیر از این انجام شده؟
کل تاپیک و pdf در مورد فهم و توضیح چگونگی این کار است.
کافی است pdf موجود را مجدد و با دقت بیشتری مرور کنید:
http://support.h02.ir/fwlink/?LinkId=1001574597

موفق باشید.

----------


## rezano

با سلام

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

دمت گرم داداش  :قلب:  :تشویق:

----------


## sajjad2

ممنون . 
حالا یک مشکل جدید چطوریمی تونم به یک آی پی دیمنامیک متصل بشم ؟  هیچ سروری با آی پی استاتیک میون دو یوزر وجود نداره . فقط با اتصال به اینترنت و داشتن آی پیآی اس پی و کد دوم می شه به هم متصل شد ؟ اصلن ممکنه ؟

----------


## Keanu Reeves

سلام

هرچی توی سایت و کلا نت گشتم منبع درست و حسابی که قشنگ توضیح داده باشه در مورد Delegate ها و EventHandler ها ندیدم
توی MSDN هم رفتم ولی انگلیسی مون هم که خوب نیست  :گریه:  دست و پا شکسته چیه چیزهایی معنی کردم ولی دقیقا چیزی نفهمیدم.

اگه میشه خودتون در مورد این 2 تا توضیح بدید که کلا کاربردشون چیه و توی این کدی که شما نوشتید چه کاری انجام میدن ؟

لطفا کمک کنید 


using System;

namespace CS_1
{
    public interface IChat
       : System.IDisposable
    {

        event MessageEventHandler Recived;
        event System.EventHandler EnabledChange;

        System.Net.IPEndPoint EndPoint { get; set; }
        bool Enabled { get; set; }
        void Send(string msg);

    }
    //__________________________________________________  ____________________


    public class MessageEventArgs
        : System.EventArgs
    {

        public readonly string Message;

        public MessageEventArgs(string message)
        {
            this.Message = message;
        }

    }
    //__________________________________________________  ____________________


    public delegate void MessageEventHandler(object sender, MessageEventArgs msg);
    //__________________________________________________  ____________________

}


منتظر جواب هستم  :خجالت:  :کف کرده!:

----------


## __H2__

سلام



> حالا یک مشکل جدید چطوریمی تونم به یک آی پی دیمنامیک متصل بشم ؟ هیچ سروری با آی پی استاتیک میون دو یوزر وجود نداره . فقط با اتصال به اینترنت و داشتن آی پیآی اس پی و کد دوم می شه به هم متصل شد ؟ اصلن ممکنه ؟


اینترنت و شبکه وابستگی بسیار شدید و غیر قابل گسستی به IP دارد.
IP نشانی رایانه مورد نظرتان است.
بدون داشتن IP هیچ عملی نمیتوان انجام داد.
دور زدن ان ممکن نیست.

=====

در واقع شما باید دنبال راه کارهایی برای بدست اوردن IP باشید.
مهم ترین راه موجود DNS است که به سرورها نام های یکتا تخصیص میدهند (مثل google.com یا microsoft.com و...) و نام به سرور DNS استعلام داده میشود و جواب ان IP آن سرور خواهد بود.

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

=====

در برنامه هایی مثل چت های yahoo و google و microsoft و... اینطور نیست که دو طرف چت مستقیم به هم وصل شوند.
در واقع این برنامه ها هر دکدام به سایت اینترنتی مشخص با نام مشخص متصل میشوند که IP این سایتها به راحتی با DNS قابل تحصیل است.

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

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

اگر بین دو رایانه دو کاربر عادی در اینترنت بدون هیچ سرور کمکی بخواهید ارتباط برقرار کنید.
تنها راه ان است که حداقل برنامه IP رایانه خودش را جایی به کاربر نشان دهد تا کاربر بتواند آن IP را با تلفن و به صورت شفاهی به دوست دیگر خودش اعلام کند و او در برنامه خود وارد کند و ارتباط برقرار شود!!!!!!
تازه این هم فقط وقتی تضمین دارد که فرد حداقل IP Valid داشته باشد (مثلا Dialup نباشد!)
اصولاً کار جامع و کارآمد و جالبی نیست!

موفق باشید.

----------


## __H2__

سلام مجدد
چون توضیح سوال قبلی و بعدی زیاد بود بهتر دیدم برای وضوح بیشتر دز پست جدیدی سوال دوم را جواب دهم...



> در مورد Delegate ها ... اگه میشه خودتون در مورد این 2 تا توضیح بدید


(((
مطلب زیر را قبلاً در سایت دیگری قرار داده بودم ولی چون دیدن کدها در آن سایت بدون عضویت ممکن نیست، مجدد کپی مطلب خودم را اینجا درج میکنم
)))

delegate ها اشاره گر توابع هستند.
یعنی آدرس شروع کدهای تابع را در RAM در خودش دارد.
در واقع میتوانید با delegate یک تابع را جابه جا کنید.
مثل یک نوع shortcut به محل ان تابع.

کد نمونه:

//C#‎.Net
public delegate int Name1(int i);

public void Run(Name1 handler)
{
    for (int i = 0; i <= 10; ++i)
    {
        int y = handler(i);
        System.Diagnostics.Debug.WriteLine(y);
    }
}

public int F1(int i)
{
    return i * i;
}

public int F2(int i)
{
    return 2 * i;
}

public void Main()
{
    this.Run(new Name1(this.F1));
    this.Run(this.F1);

    this.Run(new Name1(this.F2));
    this.Run(this.F2);
}

'VB.Net
Public Delegate Function Name1(ByVal i As Integer) As Integer

Public Sub Run(ByVal handler As Name1)
    For i As Integer = 0 To 10
        Dim y As Integer = handler(i)
        System.Diagnostics.Debug.WriteLine(y)
    Next
End Sub

Public Function F1(ByVal i As Integer) As Integer
    Return i * i
End Function

Public Function F2(ByVal i As Integer) As Integer
    Return 2 * i
End Function

Public Sub Main()
    Me.Run(New Name1(AddressOf Me.F1))
    Me.Run(AddressOf Me.F1)

    Me.Run(New Name1(AddressOf Me.F2))
    Me.Run(AddressOf Me.F2)
End Sub

دقت کنید که تابع Run یک اشاره گر تابع میگیرید و آن را در داخل خودش اجرا میکند ...
تابع F1 و F2 هم دو نمونه تابع مطابق الگوی امضای دیجیتال Name1 است که اشاره گرشان میتواند در متغییری از Name1 جا شود و یا منتقل شود.

در واقع در یک متغییر عادی شما ساختارها(struct) و اشیا(class) ها را جابه جا میکنید و در متغییری از نوع delegate میتوانید یک تابع را جا به جا کنید!

بعد از توضیح فوق اگر همچنان مشکلی بود، بفرمایئد.

----------


## Keanu Reeves

سلام

آقا شرمنده

شما اومدید از اول قدم به قدم همه چیز رو گفتید
بعد که رسیدید به Asynchronous یه توضیح مختصر دادید و کل کامل برنامه رو گزاشتید

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

ولی حالا که نگاه می کنم می بینم اوضاعم خیلی خرابه این طور اگه پیش برم تا سال دیگه هم نمی تونم یاد بگیرم

گفتم اگه میشه یه کم موضوع رو باز تر کنید 
مثلا Asynchronous  و استفاده از متدهای BeginXXXXX و .... و AsyncCallback رو بیشتر توضیح بدید
توی کدتون هم اصلا کامنت برای متد ها و متغییرها نگزاشته بودید .

----------


## __H2__

سلام



> بعد که رسیدید به Asynchronous یه توضیح مختصر دادید و کل کامل برنامه رو گزاشتید


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




> مثلا Asynchronous و استفاده از متدهای BeginXXXXX و .... و AsyncCallback رو بیشتر توضیح بدید


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


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


درک متد های BeginXXXXX و EndXXXXX:
اگر تابعی به صورت عادی مانند Func1(arg As InpType) As OutType داشته باشید، وضعیت کاری همچین تابعی حتماً برایتان مشخص است.
مقادیری مانند InpType میگیرد و یک مقدار مانند OutType پس میدهد.
همچین تابعی با همین ریسمان (اجازه دهید بگویییم کارگر) جاری کارش را انجام میدهد و وقتی هم کارش تمام شد OutType را پس میدهد، گمان نکنم تا اینجا را مشکلی داشته باشید.

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


نتیجتاً برای این کارهای زمان بر و اینکه برنامه نخوابد (تنها ریسمان کارگر موجود را برای انجام یک کار از دست ندهیم و اعمال دیگر روی هوا بماند) از چند ریسمانی استفاده میکنیم (به نوعی چند نفر را در شرکتمان استخدام میکنیم تا یکی را که دنبال کاری فرستادیم یکی دیگر برای کارهای جاری حضور داشته باشد.)


دات نت اجازه اینکه خودتان مستقیماً ریسمان جدید بسازید و آن را به کاری مشغول کنید را میدهد ولی بعضاً برای راحتی استفاده و برای متدهایی که حدس میزند برنامه نویس بخواهد انها را در ریسمان مجزایی اجرا کند خودش اینکار را فراهم کرده و آماده میکند و تحت دو تابع مانند
BeginFunc1(arg As InpType, callback As System.AsyncCallback, state As Object) As System.IAsyncResult
و
EndFunc1(asyncResult As System.IAsyncResult) As OutType
ارائه میدهد.

BeginFunc1 پارامتر InpType مورد نظر را گرفته و کار را انجام میدهد (حالا هر چقدر که طول بکشد) وقتی کارش تمام شد AsyncCallback را که ما به آن داده بودیم اجرا میکند و ما میتوانیم در AsyncCallback مان EndFunc1 را اجرا کنیم و مقدار نتیجه OutType را از آن بگیریم.

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

تنها نکته ای که میماند توضیح در مورد AsyncCallback است که BeginFunc1 ان را علاوه بر InpType از ما گرفته.
AsyncCallback یک Delegate است، Delegate ها همان اشاره گر به توابع هستند که در سایر زبان ها هم با اشکال مختلف داریم.
یک شی نمونه سازی شده Delegate (مثل AsyncCallback) یک متغییر است که آدرس و یا اگر برایتان قابل فهم تر است Shortcut یک تابع را در خود نگاه میدارد.
با داشتن یک Delegate ما یا دات نت یا هر کدی دیگری میتواند آن تابع را اجرا کند.


در واقع دات نت یک AsyncCallback از ما میگیرد تا بداند وقتی کار تمام شد چگونه به ما اطلاع دهد و چه کد و چه کاری را در پایان کار انجام دهد.


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

AsyncCallback همین است.


شما تابعی با الگوی امضإ (Func2(ar As System.IAsyncResult مینویسید و کاری را که میخواهید در پایان این فرآیند اجرا شود در ان مینویسید (از جمله گرفتن نتیجه کار از EndFunc1) و در زمان اجرای BeginFunc1 آدرس یا Shortcut یا Delegate این را به BeginFunc1 میدهید تا آن بداند، در پایان کار چه کدی را اجرا کند.

==============

من سعی ام را کردم که در کوتاه ترین حد ممکن موضوع را برایتان روشن  کنم.
چند ریسمانی و کنترلر و ارتباط و سینک ریسمان های متعدد با هم و... و... جزئیات بیشتری دارد که دات نت به حق بسیار بسیار کامل تمام این امکانات را در فضای System.Threading قرار داده.

در کل مطالب فوق من اصلاً هیچ چیز از تجهیزات و امکانات System.Threading را توضیح ندادم و (البته هدف تاپیک هم در این مورد نبوده) ، بحث چند ریسمانی یک مبحث مجزا و پرکاربرد برنامه نویسی است و در هر جایی هم قابل استفاده است.

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

----------


## Mehran Badami

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

----------


## mr_nekooei

سلام
آقا دست شما حسابی درد نکنه من که حسابی کارم راه افتاد.

----------


## n_m_1365

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

----------


## vanguard

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



> سلام
> 
> دقیقاً اصول یک برنامه سرور محور همین است که گفتید و خیلی خوب هم متوجه شدید.
> 
> در اصل خیلی بهتر است پیغام شما به جای یک String ساده یک class یا struct باشد مثلاً با اعضای زیر:
> ID_Sender-Int32
> ID_Receiver-Int32
> ID_MessageType-Byte
> (EndHeader-9Byte)
> ...

----------


## behnam_bwg

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

https://barnamenevis.org/showthread.p...B1%D9%88%D8%B1

----------


## systam

سلام
من با این کد زمانی کلاینتی  فرمان پرینت رو  ارسال میکنه مشخص کنه کدام سیستم بوده
 Dim LocalIP As String = Nothing        Dim IPHostEntry As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHost  Name())
        For Each IPAddress As System.Net.IPAddress In IPHostEntry.AddressList
            If IPAddress.AddressFamily.ToString() = "InterNetwork" Then
                LocalIP = IPAddress.ToString()
            End If
        Next
        Return LocalIP
برنامه روی توی سیستم که اجرا میکنم درست نمایش میده ولی  از سیستم های دیگه که پرینت میزنند نام سیستمی که برنامه اجرا هست رو  نمایش میده

----------


## behnia_k

سلام
من از دات نت استفاده نمی کنم. وی سوالی داشتم.
اکر روی کارت شبکه یک کامپیوتر چند ای پی ست کرده باشیم مثلا 
xxx.xxx.xxx.123
xxx.xxx.xxx124
xxx.xxx.xxx.125

و بخواهیم به سروری با آدرس xxx.xxx.xxx.126 وصل شویم

کلاینت برای وصل شدن ار کدام ای پی استفاده میکند؟

----------

