انجمن‌های فارسی اوبونتو

لطفاً به انجمن‌ها وارد شده و یا جهت ورود ثبت‌نام نمائید

لطفاً جهت ورود نام کاربری و رمز عبورتان را وارد نمائید


توزیع گنو/لینوکس اوبونتو ۲۰ ساله شد 🎉

نویسنده موضوع: SocketProgramming  (دفعات بازدید: 3378 بار)

0 کاربر و 1 مهمان درحال مشاهده موضوع.

آفلاین علیرضا طالقانی

  • High Hero Member
  • *
  • ارسال: 2373
  • جنسیت : پسر
  • القدس لنا، والنصر لنا!
    • Take it easy
SocketProgramming
« : 04 امرداد 1387، 09:58 ق‌ظ »
سلام! این ی برنامه ی سوکت هستش که ب تازگی نوشتم و سعی هم کردم ی کامنت مرتب براش نوشته باشم!
مزیت این کد در این هستش ( کلا بحث سوکت )  که یک ایده ی کلی داریم و اون ایجاد سوکت هستش و بر قراری ی ارتباط! بعد از این دیگه هر برنامه ی کلانت/سرور ای رو میشه تحت این قالب گنجانید.

نمی دونم اصلا تا چ حد براتون جالب باشه! اما من که خیلی لذت بردم!   
ضمنا این نسخه ی سرور اش هست و تحت زبان سی و برای کلانت هم از telnet  به روشی که در آخرش آمده میشه استفاده کرد.
:)
/*
 هدر های مورد نیاز
 نکته:: روی لینوکس کار کردم این رو ! اما برای ویندزو فقط کافی ی که یک هدر بهش اضافه بشه
#include <winsock.h>
 همین و اگه مایل بودید می تویند ساختار اش رو هم در قسمت مربوطه در تابع main فعال کنید
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

#define SERVERPORT 3490  //  تعریف شماره ی پورت پیش فرض برای سمت سرور
#define BACKLOG 10  // تعیین حداکثر تعداد ارتباط همزمان


void sigchld_handler(int s)  // این تابع برای حذف پروسه هایی ی که معلق مانده و یا زامبی شده
{
while (waitpid(-1, NULL, WNOHANG) > 0);
}

int main(int argc,char** argv){
//در این قسمت متغییر هایی رو که ز طریق ترمینال به داخل برنامه پاس شده رو نمایش دادم!
// البته هدف برای توسعه اش بود! مثلا پورت سرور رو هم بشه دریافت و تغییر داد
// اما فعلا هیچ پیداه سازی ای نشده و فقط ی پیش نمایش ز ورودی هاست
printf("\n****************************************\n");
printf("\n***********AliRezaTaleghani*************\n");
printf("\n****************************************\n");
printf("These are the arguments ,that passed in:\n");
int x;
for (x=0 ; x<= argc ; x++){
printf("%d - %s * \n",x , argv[x]);
}
printf("\n****************************************\n");
// و تعریف متغییر های داخل برنامه
FILE *dataFilePointer;   //  ی اشاره گر به فایل دیتای خارجی
int serverSocketfd, peerSocketfd; // دوتا اشاره گر عددی که بعد ب سوکت ها نگاشت می شوند
struct sockaddr_in serverAddr;  // دوتا ساختمان داده از نوع سوکت
struct sockaddr_in peerAddr;   // دوتا ساختمان داده از نوع سوکت
socklen_t sin_size;    // ی متغییر که فکر کنم اینم عددی باشه! اما از نوع  اندازه ی سوکت
struct sigaction serverSignalAction;    // ساختمان داده از نوع بازخورد های سیگنال های بین پروسه ای
int yes =1;        // ی متغییر عددی برای بررسی وظعیت اجرای پروسه
const int buffSize=100;       // ی ثابت برای تعیین اندازه ی بافر در بخش دریافت داده
char buff[buffSize];     // ی آرایه ی کاراکتری  با برای دریاف
int recvbytes;       // طول رشته ی دریافتی

int index=0;    // متغییر عددی برای پیمایش لیست کاندیدا
int ListSize=5;  // طول لیست کاندیدا
char vote[20];   // اینم فعلا یادم نیست چی بود :D شاید حذف اش کرده باشم در برنامه!‌اگه بود که همون جا توضیح می دم


// ی ساختار برای نگهداری  اطلاعات افراد
struct {
char name[50];   // نام کاندید
int vote;  // میزان رای کنونی
}candidates[ListSize];        // این قسمت هم ب طور اتوماتیک ی آرای ی با ندازه تعیین شده و از نوع اشاره گر به همین ساختار درست می کنه

/*

    |-index-|-Ptr 2 stracture-|
|-index-|-Ptr 2 stracture-|
|-index-|-Ptr 2 stracture-|
|-index-|-Ptr 2 stracture-|
|-index-|-Ptr 2 stracture-|

ی همچین لیست ای رو میشه تصور کرد براش

*/

/*
در مراحل بعدی شاید اولش یکمی شلوغ ب نظر بیاد !
اما فقط ی ساختار کنترل خطا هستش که در همه ی قدم هاتکرار شده
یعنی در داخل شرط ی عملی انجام شده و اگر نتیجه اش منهای یک باشه!‌یعنی خطا و سپس خطا د
 در خروجی نمایش داده میشه و اجرا ی پروسه متوقف میشه.
 مثلا در قدم اول::
 (serverSocketfd = socket(AF_INET, SOCK_STREAM, 0))
 فقط ی آدرش اشاره گر به سوکت هستش که در متغییر عددی ی خودش ذخیره شده
حالا اگه این عمل درست و موفق انجام نشه! مقدار منهای یک بر میگرده که ب معنای خطا هستش
و ارور هم در مغییر عمومی ی اشکالات که در خط بعد به خروجی منتقل شده
و سپس توفق اجرا
نکته:: در راهنمای توابع عدد مربوط ب خطا معین شده! معمولا منهای یک هستش
 
*/


/*
 این ساختار برای ویندوز هستش که من شرایط تست ش رو نداشتم! اما نباید خیلی چیز خواهی باشه
 #include <winsock.h>
{
    WSADATA wsaData;   // if this doesn't work
    //WSAData wsaData; // then try this instead
    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
        fprintf(stderr, "WSAStartup failed.\n");
        exit(1);
    }
 */




/*
 ایجاد سوکت برای آدرس دهی در شبکه ی اینترنت و بر اساس تی-سی-پی
 */
if ( (serverSocketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("socket");
exit(1);
}
/*
 این یکی رو با اون یکی! یعنی سیگنال !‌خودم خیلی تسلط ندارم! البته حذف اشون هم کنیم هیچ ا
 هیچ اتفاقی نمی افته!‌چون کارمون اینقدر ها هم بزرگ و سنگین نیست !
 اما ی مختصر اگه بگم::
 این تابع میاد و بررسی می کنه ک آیا قبلا همین سوکت باز شده یا نه! و اگه شده باشه و
 به صورت دستی برنامه تون رو متوفق کرده باشید و با احتمال صفر درصد کرنل هم سوکت رو نه بسته باشه!
 مجدد همون سوکت رو براتون بدست می گیره
 */
if (setsockopt(serverSocketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
perror("setsockopt");
exit(1);
}

// پر کردن ساختار سوکت مربوط به سمت سرور
serverAddr.sin_family = AF_INET;   // خانواده ی پروتکل برای آدرس دهی ی نت
serverAddr.sin_port = htons(SERVERPORT);   // تبدیل پورت سرور به نوع ذخیره ی اول با ارزش ترین مقدار
serverAddr.sin_addr.s_addr = INADDR_ANY;  // تعیین آی-پی ی سیستم ! این مقدار در متغییر سراسری و توسط کرنل ذخیره شده
memset(serverAddr.sin_zero, '\0', sizeof(serverAddr.sin_zero));   // صفر کردن مابقی ی رشته
/*
 پی نوشت::
 اگه خاطر اتون باشه! سوکت بر اساس ساختار sockaddr
 کار می کنه و برای راحتی ی کار از ساختار واسط sockadd_in
 داریم استفاده می کنیم! در هنگام تبدیل واسط به ساختار اصلی ی مقداری از رشته ی آدرس
 روباید صفر کرد تا استاندارد بشه!
 فکر می کنم در ساختار پایه ی رشته ی چهارده بایتی بودش که هشت تای آخرش باید صفر می شد.
 */

/*
در این قسمت هم که سوکت گرفته شده از کرنل رو با
مشخصات سمت سرور ترکیب و در کرنل ثبت می کنیم.
البته اون ساختار کنترلی ی اول هم که توضیح دادم
باهاش ترکیب شده.
پی نوشت:: همون if و مقدار بازگشتی ی تابع رو عرض کردم
*/

if (bind(serverSocketfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1){
perror("bind");
exit(0);
}
/*
 مرحله ی بعد هم از کرنل می خواد که روی پورت گوش بده و البته دریافتی ها رو هم به این پروسه بفرسته
 بیشتر از ده تا رو معلق می کنه و در صف انتظار نگه می داره که تویط BACKLOG معین شده
 ساختارکنترلی رو هم دیگه مجدد نگم ! هنوز داریم اش ;)
 */


if (listen(serverSocketfd,BACKLOG) == -1){
perror("listen");
exit(1);
}


/*
   این قسمت مربوط به پروسه های زامبی شده است که از حافظه خارج اشون می کنه
*/
serverSignalAction.sa_handler = sigchld_handler;
sigemptyset(&serverSignalAction.sa_mask);
serverSignalAction.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &serverSignalAction, NULL) == -1){
perror("sigaction");
exit(1);
}

/*
و از این قسمت به بعد وارد ی لوپ بی نهایت خواهید شد ! برای هر درخواست ارتباط که تابع listen
 قبول می کنه و به داخل راه میده بایستی ی کپی از پورسه ایجاد کنیم ومدیریت اش رو به خودش واگذار کینم
 و پروسه ی اصلی منتظر درخواست بعدی بشه

 */

while(1){
sin_size =  sizeof(peerAddr);   // این هم اگه در بخش تعریف متغییر ها خاطر انون باشه طول ی سوکت بودش
/*
در قدم بعدی تابع accept با گرفتن اعلام در خواست از کرنل،‌ مشخصات سوکت طرف
تماس گیرنده رو در ی  ساختار ثانویه ی ذخیره می کنه
*/
if ( (peerSocketfd =  accept(serverSocketfd, (struct sockaddr *)&peerAddr, &sin_size)) == -1){
perror("accept");
continue;
}
// اینجا هم فقط ی خروجی ی ساده است که IPتماس گیرنده رو در خروجی ی سرور ثبت می کنه
printf("server: got connection from %s\n",inet_ntoa(peerAddr.sin_addr));

/*
و بحث شیرین فورک
قدم بعدی دقیقا ی کپی از مابقی ی پروسه ب باقی مونده ب اضافه ی تغییر هایی که در بالاتر تولید شده
بود رو تولید می کنه. این پروسه ی جدید ب طور موازی با پروسه مادر پردازش خواهد شد.
و خب این یعنی ما الان دوتا پروسه داریم
نکته:: پروسه ی مادر رو اگه توجه کنیم در ی حلقه ی بی نهایت هستش! پس با هر درخواست جدید
ی پروسه ی دیگه هم اصافه می کنه و این یعنی تعدد پروسه ها!
خب چطوری اینا رو جدا کنیم و با هم تداخل نداشته باشند؟ :-?
ساده است! :)
شماره ی پروسه
البته اینجا کمی قشنگ تر این کار انجام شده!
اصل کار این طوری ی که وقتی تابع فورک اجرا میشه! ی خروجی ی عددی بر می گردونه
این عدد شماره ی پروسه ی فرآیند فرزند هستش.
خب اگه ی عدد باشه! یعنی بک فرزند هستش و اگه نه یعنی والد هستش
نکته:: این درسته که ی عدد هستش ! اما از نوع شماره ی پروسه
مثل کاراکتر که ی نوع خاص هستش!‌ این هم ی حالت خواص داره
پس با نقیض کردن اش در این جا تونستیم از فرزند بودن ش آگاه بشیم.

http://www.manpagez.com/man/2/fork/
لینک هم در مورد همین تابع بودش
*/

// دقت کنید که تمام فرآیند های مربوط به پروسه ی فرزند در بلوک شرط آمده
if(!fork()){
close(serverSocketfd);
/*
با توجه به اینکه الان در پروسه ی فرزند ایم! پس اشاره گر به سوکت سرور رو نیازی نداریم و برای
اطمینان می بندیم ش
 */

if ( (send (peerSocketfd, "Hello, Give me Ur Real Name,plz:\n", strlen("Hello, Give me Ur Real Name,plz:\n") , 0)) == -1)
perror("send");

/*
در قدم اول ی پیغام متنی برای کسی که وصل شده فرستادیم
توسط تابع ارسال send
اولین آرگومان اش سوکت سمت مشتری هستش که با تابع accept بدست آوردیم اش
دومی ی رشته هستش و سومی هم طول رشته ای که باید ارسال بشه
*/
if( (recvbytes = recv (peerSocketfd, buff , buffSize-1 , 0)) && recvbytes == -1)
perror("recv");
/*
بعد هم منتظر پاسخ سوال مون از مشتری هستیم.
بازم اول سوکت مشتری رو به تابعد دریافت فرستادیم!
بعد خود بافر که از قبل ساخته بودیم اش و البته اندازه اش
کاهش یک واحد از اندازه ی بافر هم در قدم بعدی معلوم میشه
خب ما داریم ی رشته میگریم و در بافر قرار می دهیم
حالا اندازه ی بافر ما مثلا ده واحد باشه و طول رشته ی ما پنج واحد

|*|*|*|*|*| | | | | |
خب حالا اگه این رو بخواهی به خروجی بفرستیم! سیستم همه ی ده تا رو چاپ می کنه و ما همه اش
نمیخواهیم. همیشه مهم نیست! ولی گاهی ی چیزایی در حافظه از قبل بوده و در خروجی
ی علائمی رو می بینم که نیازی بهشون نداریم!یعنی خروجی رو معمولا نا معتبر می کنه
و اگه یادتون باشه انتهای هر رشته باید ب ی علامت خواصی ختم می شد.
خب ما هم در قدم قبلی همین کار رو کردم و ی جا براش اون علامت خواص نگه داشتیم.
حالا میاییم و به مقدار کاراکتر های دریافتی که در قدم قبلی از تابع دریافت بازگشت
داده شده! محل اون علامت رو محاسبه و درج می کنیم.
و بعدش بافر رو به خروجی منتقل کردیم.
*/
buff[recvbytes]='\0';
printf("%d bytes, -which is the name- recived:=>%s", recvbytes, buff);

/*
اوکی! حالا می رسیم به اصل داستان
رای گیری::

اول عرض کنم که ی  بانک ساده ی متنی روایجاد کردیم!
الان یادم آمد که اون فایل بانک رو آپلود نکرده بودم! شرمنده
برای تولید اون هم از همین برنامه استفاده کرده بودم! ولی خب در حین نوشتن کد بود کد
اولیه خیلی با این فرق می کرد. اگه با نوت-پد باز کنید اش! می بینید که خیلی ساختار ساده داره
پایین تر حتما توضیح می دم
*/

// قدم اول باز کردن ی اشاره گر به ی فایل بیرونی هستش
if ( (dataFilePointer = fopen("data.dat","a+b")) == NULL){
printf("can't OPen the file.\n" );
exit(1);
}

/*
حالا به اندازه ی  لیست مون و بر اساس ساختار واحد های اطلاعات امون از فایل می خونیم
 
 توضیح اینکه با دستور های fscanf و sprintf ب جای خروجی ی استاندار! میشه در یک فایل
 کار کرد.
 در این مرحله با خودن از فایل و بر اساس ساختار معین ای که بهش پاس کردیم!از فایل دیتا
 اطلاعات رو خوندیم .
 یعنی به ترتیب ی رشته و ی عدد و در محل خودشون در اون جدولی که در بالا تعریف کرده بودم ! ذخیره اش کردیم
 و بعد با افزایش پیمایش گرد! نفر بعدی رو خواندیم
 
 
 پی نوشت::
 اول اش اصلا فایل نداشتم و خود آرایه رو ایجاد کرده بودن‌! ب صورت داخلی و مقداری دهی
 بعد با دستور fprintf اون رو در یک فایل خارجی ذخیره کردم که همین فایل دیتا مون شده
 و از این به بعد ازش استفاده کردم.
 بازم شرمنده ک یادم رفته بود اون رو هم بالاگذاری کنم! در پایین همین صفحه الان الصاق شده
 کافی ی در همین محل فایل اصلی که کامپایل می کنید!‌قرار اش بدید
*/
 index=0 ;
while( index<ListSize){
fscanf(dataFilePointer,"%s %d", &candidates[index].name,&candidates[index].vote );
index++;
}
fclose(dataFilePointer);  //  بعد از اتمام خواندن فایل! اشاره گراش رو می بندیم


/*
 این قدم هم ساده است! فقط یکمی به خاطر اینکه باید همه چیز رو به رشته ها تبدیل می کردم و ی
 ساختار مناسب مثل شماره ی ردیف کاندید بهش اضافه می کردم! شاید به نظر شلوغ میاد.
 اگه بایکمی دقت بخونید اش! خیلی ساده ست
 و قدم به قدم ی جدول ماند از کاندیدا رو برای مشتری می فرسته
*/

index = 0;
while ( index < ListSize  ){
sprintf (vote ,"%d - Curent Voted is: %d *** ",index , (candidates[index].vote) ) ;
send (peerSocketfd, vote,  strlen(vote) , 0);
send (peerSocketfd, candidates[index].name, strlen(candidates[index].name) , 0);
send (peerSocketfd, "\n" , strlen("\n") , 0);
printf("index %d with the value of %s\n", index, candidates[index].name);
index++;
}


// وقتی جدول تمام شد! از کاربر می خواد که یک شماره ردیف رو انتخاب کنه و برگردونه
send (peerSocketfd, "\nPlz, select one of the candidates code.\n" , strlen("\nPlz, select one of the candidates code.\n") , 0);
// مجدد به همون روشی که در دریافت قبلی هم گفته شد!‌مقدار بازگشتی رو دریافت می کنیم
if( (recvbytes = recv (peerSocketfd, buff , buffSize-1 , 0)) && recvbytes == -1)
perror("recv");

buff[recvbytes]='\0';
/*
 چون از تل-نت برای کلاینت استفاده کردیم!  تراکنش ها کاراکتری ی و مقدار بازگشتی مون! درسته که
 در ظاهر عدد هستش!اما ماهیت کاراکتری داری
 با تابع بعدی به مقدار عددی تندیل کردیم ش تا بشه باهاش محاسبات کرد
 */
index = atoi(buff);
printf("Candidate %d  selected for update.\n", index);
// اسم کانددای انتخابی رو در خروجی ی سرور نمایش دادیم
candidates[index].vote += 1;
// و در خط بالا مقدار رای اون کاندید رو یکی افزارش دادیم و در خط بعدی اون رو هم در خروجی نمایش دادید
printf("%s %d\n",candidates[index].name,candidates[index].vote);

// خب مشکل ای که اول داشتیم و باعث شد به فایل بیرونی احتیاج پیدا کنیم اینجا بود
/*
 همه چیز در حافظه بود! پروسه ها مجزا بود! لذا نتایج جایی باقی نمی موند
 پس در هر مرحله ی رای گیری ی بار فایل قبلی رو در اینجا حذف می کنیم ومجدد با اطلاعات به روز شد
 شده در حافظه اون رو از اول ایجاد می کنیم تا برای بعد امون بمونه و البته سایر پروسه ها
*/
if (remove("data.dat"))
printf("can't remove the DataBase file\n");
else
printf("removed the DataBase file\n");
// مجدد ی اشاره گر به فایل می سازیم که باعث ایجاد فایل جدید و خالی میشه
if ( (dataFilePointer = fopen("data.dat","a+b")) == NULL){
printf("can't OPen the file.\n" );
exit(1);
}

/*
 اندیس پیمایش گر لیست رو صفر کرده و مجدد لیست رو از حافظه خونده و با توجه به ساختار اش
 در فایل خالی مون ذخیره می کنیم
 این همون روشی بود که گفتم اولین مرتبه برای تولید بانک اولیه مون استفاده کردم
 البته ب صورت دستی و در قسمت های اولیه ی ایجاد لیست خام
*/
 index=0 ;
while( index<ListSize){
fprintf(dataFilePointer,"%s %d", candidates[index].name,candidates[index].vote );
index++;
}
fclose(dataFilePointer);

// اوکی بعد از پر کردن فایل! اشاره گر اش رو می بیندی


close(peerSocketfd);

// کارتمام شده و سوکت پروسه ی فرزند رو هم می بیندم  و خروج از شرط هم در ادامه اش
exit(0);
}
close(peerSocketfd);

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

یعنی وقتی منشعب شد فرزند ! بلافاصله در همون محدوده ی زمانی که در پروسه ی فرزند سوکت اصلی رو بسته بودیم
عمل بستن سوکت فرزند هم در پروسه ی والد انجام شده و پروسه ی والد به همون بخش انتظار اتصال جدید بازگشت و منتظر هستش.
*/

}

return 0;
}
/*
 و تمام
 خسته نباشید
 */


و یک فایل هم که الصاق می کنم!‌ب عنوان بانک اطلاعات پایه اش هستش.
کافی ی فایل بالا رو بگیرید و در همون پوشه ای که این برنامه رو کامپایل می کنید قرار بدید
.ShayneIsTheOneWhoIsAlwaysAlone
terminal@world-server:~$ sudo aptitude remove --purge Israel

آفلاین hosseinyounesi

  • Newbie
  • *
  • ارسال: 13
پاسخ به: SocketProgramming
« پاسخ #1 : 04 امرداد 1387، 11:56 ق‌ظ »
عالی بود  \\:D/
بازم از این کارا بکنین.

آفلاین علیرضا طالقانی

  • High Hero Member
  • *
  • ارسال: 2373
  • جنسیت : پسر
  • القدس لنا، والنصر لنا!
    • Take it easy
پاسخ به: SocketProgramming
« پاسخ #2 : 04 امرداد 1387، 01:39 ب‌ظ »
عالی بود  \\:D/
بازم از این کارا بکنین.
:P  عمرا!  ;)
.ShayneIsTheOneWhoIsAlwaysAlone
terminal@world-server:~$ sudo aptitude remove --purge Israel

آفلاین کسری کشاورز

  • High Sr. Member
  • *
  • ارسال: 608
  • جنسیت : پسر
  • Don't Look Back With Linux
پاسخ به: SocketProgramming
« پاسخ #3 : 04 امرداد 1387، 02:23 ب‌ظ »
با این کع هیچی دربارش نمی‌دونم اما ممنون
راستی C رو از کجا یاد گرفتی ما نمی دونستیم؟!منم برم یاد بگیرم....

آفلاین علیرضا طالقانی

  • High Hero Member
  • *
  • ارسال: 2373
  • جنسیت : پسر
  • القدس لنا، والنصر لنا!
    • Take it easy
پاسخ به: SocketProgramming
« پاسخ #4 : 04 امرداد 1387، 02:37 ب‌ظ »
با این کع هیچی دربارش نمی‌دونم اما ممنون
راستی C رو از کجا یاد گرفتی ما نمی دونستیم؟!منم برم یاد بگیرم....
بسی رنج برد ام در این سال سی ....     حافظا :D
خیلی بلد نیستم ! ولی از روی ی کتاب قدیمی و البته باقی شم مستر گوگل
;)
.ShayneIsTheOneWhoIsAlwaysAlone
terminal@world-server:~$ sudo aptitude remove --purge Israel

آفلاین Behnam Golds

  • High Hero Member
  • *
  • ارسال: 1368
  • جنسیت : پسر
پاسخ به: SocketProgramming
« پاسخ #5 : 04 امرداد 1387، 03:27 ب‌ظ »
عالی   بود   ،    هم  خوب   comment  زدی    هم    خوب   کد   زدی   ،   ترو  تمیز  هم   کامپایل  و   اجرا  شد  ...

آفلاین ناربه

  • ناظر انجمن
  • *
  • ارسال: 2033
  • جنسیت : پسر
پاسخ به: SocketProgramming
« پاسخ #6 : 04 امرداد 1387، 04:18 ب‌ظ »
 \\:D/ \\:D/ایول

آفلاین Linux

  • Sr. Member
  • *
  • ارسال: 296
  • جنسیت : پسر
    • تبریزلاگ
پاسخ به: SocketProgramming
« پاسخ #7 : 05 امرداد 1387، 12:58 ق‌ظ »
خوب بود  :)

Before death knock on your door,share whatsoever you have.You can sing a beautiful song? sing it,share it.
You can paint a picture? Paint,share it ...
come across a man who has not much to share