
ساخت نرم افزار با سوکت شبکه ساده – آموزش شبکه درس 17
در درس های قبل ما با اصول کار سوکت تا حدودی آشنا شدیم، در این درس قصد داریم یک نرم افزار با سوکت شبکه ساده را ایجاد کنیم که برای ساخت آن از زبان C++ استفاده کرده ایم. البته شما می توانید با استفاده از هر زبان دیگری که قابلیت کار با سوکت ها را در اختیار شما بگذارد هم این کار را انجام دهید.
نرم افزار ما دارای دو بخش است که در طرف کاربر و سرور قرار گرفته است. و هر دو سمت تقریبا از ساختار یکسانی استفاده کرده اند. طرف کلاینت ارسال کننده ساده است و طرف سرور نیز تنها شنونده است. در حال حاضر نرم افزار ما تنها یک کاراکتر پیشفرض را در خروجی چاپ می کند.
شروع به ساخت نرم افزار با سوکت شبکه
ما اکنون به شما نشان میدهیم که چطور بتوانید برنامه ساده کلاینت/سروری را پیاده کند که بتواند از رابط کاربری سوک برای ارسال و دریافت پیام بر روی اتصال ایجاد شده با پروتکل کنترل انتقال (TCP) استفاده کند. همچنین این برنامه از دیگر امکانات شبکه سیستم عامل لینوکس بهره میگیرد که ما در ادامه به معرفی آنها میپردازیم. نرمافزار ما این امکان را به کاربر میدهد که بتواند بر روی یک دستگاه تایپ کند و سپس پیامی را به کاربر دیگر در دستگاه دیگری ارسال کند. این سیستم ساده شده ای از برنامه talk در سیستم عامل لینوکس است، که بسیار شبیه به برنامههایی دیگر است که در هسته خود کار پیام رسانی را نیز انجام میدهند.
سمت کلاینت برنامه
ما کار با برنامه سمت کلاینت (کاربر) شروع میکنیم که نام را از دستگاه راه دور به عنوان یک آرگومان دریافت میکند. آن امکانات لینوکس را برای ترجمه کردن نام به آدرس IP هاست راه دور را به خدمت میگیرد. در گام بعدی انتظار میرود ساختار داده آدرس (sin
) به وسیله رابط کاربری سوکت، ساختار بندی شود. توجه کنید که این ساختار داده در زمانی تعریف میشود که ما میخواهیم از سوکت برای اتصال به اینترنت (AF_INET
) استفاده کنیم. در مثال ما، ما از پورت TCP در پروتکل کنترل انتقال (TCP) که به خوبی به عنوان یک پورت سرور شناخته شده است استفاده میکنی؛ این کار را به این خاطر انجام میدهیم که این پورت به هیچ سرویس دیگری انتساب پیدا نکرده است. در گان نهایی نیز تنظیمات اتصال را برای فراخوان کردن سوکت و اتصال به آن انجام میدهیم. در زمانی که عملیات بازگشت (Return
) انجام میشوأ، اتصال ما ایجاد شده و برنامه کاربر وارد حلقه اصلی (main loop) میشود، که در نتیجه آن نوشتهها را به وسیله ورودی استاندارد میخواند یا آنها را بر روی سوکت مورد نظر ما ارسال میکند.
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #define SERVER_PORT 5432 #define MAX_LINE 256 int main(int argc, char * argv[]) { FILE *fp; struct hostent *hp; struct sockaddr_in sin; char *host; char buf[MAX_LINE]; int s; int len; if (argc==2) { host = argv[1]; } else { fprintf(stderr, "usage: simplex-talk host\n"); exit(1); } / * translate host name into peer’s IP address */ hp = gethostbyname(host); if (!hp) { fprintf(stderr, "simplex-talk: unknown host: %s\n", host); exit(1); } / * build address data structure */ bzero((char *)&sin, sizeof(sin)); sin.sin_family = AF_INET; bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); sin.sin_port = htons(SERVER_PORT); /* active open */ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("simplex-talk: socket"); exit(1); } if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("simplex-talk: connect"); close(s); exit(1); } / * main loop: get and send lines of text */ while (fgets(buf, sizeof(buf), stdin)) { buf[MAX_LINE-1] = ’\0’; len = strlen(buf) + 1; send(s, buf, len, 0); } }
طرف سرور
طرف سرور ما کار بسیار سادهتر است. در ابتدا باید ساختار داده آدرس را که به وسیله شماره پورت خودش وجود دارد (SERVER_PORT
) پر کنیم. به خاطر آنکه ما در اینجا از هیچ آدرس IP استفاده نکردهایم، در نتیجه برنامه ما هر اتصالی را از هر کدام ازهاستهای با آدرس IPهای محلی قبول میکند. در گام بعدی سرور نخستین مراحل را طی میکند که وارد مرحله باز بودن منفعل (Passive Open
) شود؛ آن سوکت را میسازد و به آدرسهای محلی متصل میشود و در نهایت به تعداد زیادی از سوکتهایی که در حالت انتظار هستند اجازه اتصال میدهد. در نهایت حلقه اصلی برای یکهاست راه دور که تلاش برای اتصال کند منتظر میایستد، و در زمانی که این کار انجام گردید، آن را دریافت کرده و کاراکترهایی که از طریق اتصال دریافت کرده است را بر روی صفحه نمایش چاپ میکند.
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #define SERVER_PORT 5432 #define SERVER_PORT 5 #define MAX_LINE 256 int main() { struct sockaddr_in sin; char buf[MAX_LINE]; int buf_len, addr_len; int s, new_s; /* build address data structure */ bzero((char *)&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(SERVER_PORT); /* setup passive open */ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("simplex-talk: socket"); exit(1); } if ((bind(s, (struct sockaddr *)&sin, sizeof(sin))) < 0) { perror("simplex-talk: bind"); exit(1); } listen(s, MAX_PENDING); /* wait for connection, then receive and print text */ while(1) { if ((new_s = accept(s, (struct sockaddr *)&sin, &addr_len)) < 0) { perror("simplex-talk: accept"); exit(1); } while (buf_len = recv(new_s, buf, sizeof(buf), 0)) fputs(buf, stdout); close(new_s); } }