رفتن به مطلب
جامعه‌ی برنامه‌نویسان مُدرن ایران

فرهاد شیری

میانجی گر‌ها
  • تعداد ارسال ها

    19
  • تاریخ عضویت

  • آخرین بازدید

  • روز های برد

    6

آخرین بار برد فرهاد شیری در 12 آبان

فرهاد شیری یکی از رکورد داران بیشترین تعداد پسند مطالب است !

اعتبار در سایت

23 عالی

1 دنبال کننده

درباره فرهاد شیری

اساتید
توسعه‌ دهنده بَک اِند
توسعه‌ دهنده فرانت اِند
  • تاریخ تولد 20 مهر 1360

موقعیت

  • شهر
    تهران

آخرین بازدید کنندگان نمایه

96 بازدید کننده نمایه
  1. فرهاد شیری

    برای اینکه بتونید کاراکتر هایی خاصی را از بافر ورودی حذف کنید می تونید از عبارتهای باقاعده استفاده کنید.(regex) QRegExp rx("(\\d+)"); QString str = "Offsets: 12 14 99 231 7"; QStringList list; int pos = 0; while ((pos = rx.indexIn(str, pos)) != -1) { list << rx.cap(1); pos += rx.matchedLength(); } مثال بالا اعداد را از یک رشته ورودی گزینش میکنه وتو یک ظرف لیست ذخیره میکنه. برای ثبت باینری فایل هم می تونید طبق کد زیر انجام بدید... void write(QString filename) { QChar ch('A'); QFile mf(filename); if (!mf.open(QFile::WriteOnly) { qDebug() << "Could not open file for writing"; return; } QDataStream out(&mf); out.setVersion(QDataStream::Qt_4_8); out << ch; mfile.close(); }
  2. فرهاد شیری

    جهت برنامه نویسی برای سریال پورت ها البته اگر برای لینوکس بخواهید باید از کتابخانه های زیر استفاده نمایید. #include <termios.h> #include <fcntl.h> #include <sys/types.h> #include <sys/signal.h> مثلا به این شکل... #include <fcntl.h> #include <stdio.h> #include <termios.h> struct termios m_oldtio, m_newtio; bool Open(char *portName, int portSpeed) { m_nFd = open(portName, O_RDWR | O_NOCTTY|O_NDELAY ); if (m_nFd < 0) { perror(portName); exit(0); } fcntl(m_nFd,F_SETFL,O_NONBLOCK); tcgetattr(m_nFd, &(m_oldtio)); cfsetospeed(&m_newtio, B19200); m_newtio.c_cflag |=(CS8 | CLOCAL | CREAD); m_newtio.c_cflag|=PARENB; m_newtio.c_cflag&=~PARODD; m_newtio.c_oflag = ~(OPOST); m_newtio.c_lflag =0; m_newtio.c_cc[VTIME] =1; m_newtio.c_cc[VMIN] =1; m_newtio.c_cc[VSTART] = 0; m_newtio.c_cc[VSTOP] = 0; m_newtio.c_cc[VSUSP] = 0; m_newtio.c_cc[VEOL] = 0; m_newtio.c_cc[VREPRINT] = 0; m_newtio.c_cc[VDISCARD] = 0; m_newtio.c_cc[VWERASE] = 0; m_newtio.c_cc[VLNEXT] = 0; m_newtio.c_cc[VEOL2] = 0; tcflush(m_nFd, TCIFLUSH); tcsetattr(m_nFd, TCSANOW, &m_newtio); return true; } برای read , write کردن هم یکم خودتون جستجو کنید...
  3. کلاسهای وکیل : پنهان سازی جزئیات پیاده سازی به منظور جلوگیری از دسترسی به اطلاعات خصوصی و منطق خصوصی برنامه در کلاس کار مطلوبی است. قرار دادن یک کلاس وکیل برای کاربران کلاس به طوری که از رابط عمومی این کلاس آگاهی داشته باشند باعث می شود که بدون آنکه به کاربران کلاس اجازه دسترسی به جزئیات پیاده سازی کلاس اصلی را بدهیم این کاربران بتوانند از خدمات کلاس اصلی استفاده نمایند. ویا تصور کنید که شما کلاس جامعی دارید که می خواهید در اختیار سایر برنامه نویسان قرار دهید، در صورتی که از این تکنیک استفاده نکنید مجبور هستید سورس کلاس را هم در اختیار برنامه نویسان قرار دهید. در صورتی که با استفاده از این تکنیک کافی هست که شما فقط یک هدر فایل از نمای کلاس در اختیار دیگر برنامه نویسان قرار دهید و سورس کلاس را به صورت یک فایل کامپایل شده در قالب یک DLL ویا یک SO فایل در زمان اجرا به کد برنامه نویس استفاده کننده الحاق نمایید. به عنوان مثال ابتدا یک کلاس به نام Implementation.hتعریف می کنیم #ifndef IMPLEMENTATION_H #define IMPLEMENTATION_H class Implementation { public: Implementation() {}; Implementation(int v) : m_Counter(v){}; ~Implementation(){}; unsigned int GetCounter() { return m_Counter; } void SetCounter(unsigned int val) { m_Counter = val; } protected: private: unsigned int m_Counter; }; #endif // IMPLEMENTATION_H همانطور که ملاحظه می کنید در کلاس فوق یک داده خصوصی تعریف کردیم با دو متد دسترسی عمومی. و بعد یک کلاس واسط به نام Interface.h تعریف میکنیم #ifndef INTERFACE_H #define INTERFACE_H class Implementation; //forward declaration class Interface { public: Interface(int); ~Interface(); unsigned int GetCounter(); void SetCounter(unsigned int val); protected: private: Implementation *imp; }; #endif // INTERFACE_H در کلاس فوق دومتد دسترسی عمومی تعریف شده است و یک متغیر عضو اشاره گر به کلاس Implementation تعریف شده است. نکته : در این کلاس ما با استفاده از forward declaration دیگر نیازی به وارد کردن هدر فایل implementation.h نخواهیم داشت. البته توجه نمایید که اگر متغیر عضو imp راکه با استفاده از تکنیک ترکیب در این کلاس اشاره گر تعریف نمی کردیم در این صورت حتما باید هدر فایل Implementation.h را در هدر فایل Interface.h وارد میکردیم پس بنابراین استفاده از تکنیک کلاسهای وکیل بدون اشاره گر عملی نخواهد بود. و سپس پیاده سازی کلاس اینترفیس را انجام می دهیم #include "Interface.h" #include "Implemention.h" // Interface::Interface(int value) :imp(new Implementation(value)){ } void Interface::SetCounter(unsigned int val){ this->imp->SetCounter(val); } unsigned int Interface::GetCounter(){ return this->imp->GetCounter(); } Interface::~Interface() { delete imp; this->imp =nullptr ; } پس بنابراین با توجه به نکات ذکر شده تا به اینجا شما فقط کافی است که هدر فایل Interface.h را در اختیار برنامه نویسان دیگر قرار دهید و فایلهایImplementation.h و همچنین فایل Interface.cpp را به صورت کامپایل شده در اختیار برنامه نویسان دیگر قرار دهید. و در آخر هم برای استفاده از کلاس های فوق بدین ترتیب عمل خواهیم کرد. #include <iostream> #include "Interface.h" using namespace std; int main() { Interface interface(7); cout << interface.GetCounter() << endl; interface.SetCounter(15); cout << interface.GetCounter() << endl; return 0; } با استفاده از تکنیک فوق در صورتی که هر گونه تغییری در آینده در پیاده سازی منطق های برنامه داشته باشید گیرنده های کلاس بدون متوجه شدن این تغییرات به کار خود ادامه خواهند داد. دقیقا کاری که گروه استاندارد سازی زبان ++C همیشه انجام داده است و فقط نمای کتابخانه های استاندارد را در اختیار ما قرار میدهد و هرگونه تغییری در نحوه الگوریتم های این کتابخانه از دید ما مخفی هست ولازم به دانستن این تغییرات هم نخواهیم بود.
  4. 10 تکنیک کاربردی که باعث بهینه شدن عملکرد برنامه های جاوا می شود. 1. Use StringBuilder Class: به عنوان یک قاعده کلی برای تولید رشته های پیچیده با عملگر (+) ، همیشه از کلاس StringBuilder استفاده نمایید. String x = "a" + args.length + "b"; که کد فوق به شبه کد زیر کامپایل خواهدشد... همانطور که مشاهده میکنید خود کامپایلر جاوا هم عملگر + برای جمع چند رشته، به کلاس StringBuilder تفسیر میکند. 0 new java.lang.StringBuilder [16] 3 dup 4 ldc <String "a"> [18] 6 invokespecial java.lang.StringBuilder(java.lang.String) [20] 9 aload_0 [args] 10 arraylength 11 invokevirtual java.lang.StringBuilder.append(int) : java.lang.StringBuilder [23] 14 ldc <String "b"> [27] 16 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [29] 19 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [32] 22 astore_1 [x] اما چه اتفاقی می افتد، اگر بعدا، شما String خود را با رشته های جدید تغییر دهید؟ String x = "a" + args.length + "b"; if (args.length == 1) x = x + args[0]; اکنون شما StringBuilder دوم خواهید داشت، که صرفا حافظه را از پشته خود می گیرد با این کار باعث افزایش فشار بر روی GC خواهید شد. به جای آن بهتر است بنویسید: StringBuilder x = new StringBuilder("a"); x.append(args.length); x.append("b"); واگر String هایی که می خواهید به هم پیوند دهید پیچیده هستند، مرجع StringBuilder را نگه دارید و در متدهای دیگر هم از همان استفاده نمایید. 2. Avoid regular expressions : عبارات منظم نسبتا ارزان و راحت هستند. اما اگر منظور شما از بیان عبارت منظم چنین چیزی هست که به هیچ وجه قابل قبول نیست.! String[] parts = ipAddress.split("\\."); پس بهتر است به کاراکترهای معمولی با عملگر دستیابی[] مبتنی بر شاخص دست یابید. به عنوان مثال این حلقه کاملا همان کار را انجام می دهد: int length = ipAddress.length(); int offset = 0; int part = 0; for (int i = 0; i < length; i++) { if (i == length - 1 || ipAddress.charAt(i + 1) == '.') { parts[part] = ipAddress.substring(offset, i + 1); part++; offset = i + 2; } } عبارات منظم مفید هستند اما آنها پر هزینه هستند شما باید از عبارات منظم پر هزینه اجتناب کنید. مراقب استفاده از انواع روش های JDK String که از عبارات منظم مانند String.replaceAll () یا String.split () استفاده می کند، باشید. برای مثال می توانید از کتابخانه های محبوبی مانند Apache Commons Lang به جای این روشها استفاده نمایید برای دستکاری رشته ها. 3. ()Do not use iterator: نوشتن شیوه های foreach سبک جاوا 5 مناسب است. شما فقط می توانید به طور کامل در مورد داخل منطق حلقه ها فکر کنید و بنویسید ... for (String value : strings) { // Do something useful here } با این حال، هر زمانی که شما به این حلقه وارد می شوید، اگر رشته ای قابل تغییر باشد، یک نمونه جدید Iterator ایجاد خواهید کرد. اگر شما از ArrayList استفاده می کنید، این موضوع در حال تخصیص یک شی با 3 بلاک در قسمت پشته برنامه شما هست طبق تفسیر کلاس زیر... private class Itr implements Iterator<E> { int cursor; int lastRet = -1; int expectedModCount = modCount; // ... در عوض، شما می توانید حلقه معادل زیر را بنویسید و تنها یک مقدار int را در پشته صرف کنید، شاید کد کثیف تری باشد از نظر بصری، اما بهینه تر است... int size = strings.size(); for (int i = 0; i < size; i++) { String value : strings.get(i); // Do something useful here } Iterators، Iterable و حلقه foreach از دیدگاه نوشتن پذیری و قابلیت خواندن، و همچنین از دیدگاه طراحی API بسیار مفید هستند. با این حال، آنها یک نمونه جدید کوچک را در پشته برای هر تکرار تنها ایجاد می کنند. اگر تكرارهای زیادی را اجرا می كنید، می خواهید مطمئن شوید كه این نمونه بی فایده را ایجاد نمی كنید، به جای آن از تكرارهای مبتنی بر index استفاده نمایید. 4. Don’t call that method : برخی از متدها پر هزینه هستند. فرض کنید که JDBC Driver شما نیاز به انجام مشکل فوق العاده برای محاسبه مقدار ResultSet.wasNull() داشته باشد . کد چارچوب SQL homegrown شما ممکن است مانند این باشد: if (type == Integer.class) { result = (T) wasNull(rs,Integer.valueOf(rs.getInt(index))); } // And then... static final <T> T wasNull(ResultSet rs, T value) throws SQLException { return rs.wasNull() ? null : value; } این منطق اکنون ResultSet.wasNull () را هر بار که int را از مجموعه نتیجه به دست می آورد، فراخوانی می کند. اما متد getInt()می نویسد: مقدار بازگشت: مقدار ستون؛ اگر مقدار SQL NULL باشد، مقدار بازگشتی 0 است بنابراین، یک متد ساده اما در عین حال احتمالا دشوار رو به بالا می تواند این باشد: static final <T extends Number> T wasNull( ResultSet rs, T value ) throws SQLException { return (value == null || (value.intValue() == 0 && rs.wasNull())) ? null : value; } 5. Use primitives and the stack : از استفاده انواع بسته بندی ها در تعریف متغیرها از نوع اولیه اجتناب کنید.. //heap ذخیره در Integer i = 817598; //stack ذخیره در int i = 817598; وقتی که از آرایه ها استفاده می کنید، بدتر هم می شود: //heap سه شی در Integer[] i = { 1337, 424242 }; //heap یک شی در int[] i = { 1337, 424242 }; استثنا برای این قاعده وجود دارد: boolean و بایت مقادیر کافی برای ذخیره شدن توسط JDK دارند. شما می توانید بنویسید: Boolean a1 = true; // ... syntax sugar for: Boolean a2 = Boolean.valueOf(true); Byte b1 = (byte) 123; // ... syntax sugar for: Byte b2 = Byte.valueOf((byte) 123); همین امر برای مقادیر اولیه از انواع دیگر، از جمله char، short، int، long، صادق است. هرگز سازنده را بر روی انواع بسته بندی نکنید، مگر اینکه واقعا یک نمونه جدید را بخواهید. 6. Avoid recursion : زبان برنامه نویسی مدرن مانند Scala، استفاده از بازگشت را تشویق می کند، زیرا آنها ابزار بهینه سازی الگوریتم های بازگشت به تکرار تبدیل می کنند. اگر زبان شما از چنین خوش بینی ها پشتیبانی می کند، ممکن است خوب باشد. اما حتی در این صورت، کوچکترین تغییر الگوریتم ممکن است یک شاخه ای ایجاد کند که مانع بازگشت شما از بازگشت بازگشتی می شود. که البته باید امیدوار باشید که کامپایلر این خطای منطقی را شناسایی کند! در غیر این صورت، شما ممکن است بسیاری از فریم های پشته را برای چیزی که ممکن است با استفاده از چند متغیر محلی اجرا شود، هزینه کرده اید. بنابراین سعی کنید تا حد امکان از الگوریتم های بازگشتی استفاده نکنید.(تمامی الگوریتم های بازگشتی را می توان با استفاده از حلقه های for , while پیاده سازی کرد) 7. ()Use entrySet : همیشه ازentrySet ()استفاده کنید وقتی که در طول تکرار Map به دو کلید و مقدار نیاز دارید. for (K key : map.keySet()) { V value = map.get(key); } //به جای کد بالا for (Entry<K, V> entry : map.entrySet()) { K key = entry.getKey(); V value = entry.getValue(); } 8. Use EnumSet or EnumMap : بعضی موارد وجود دارد که تعداد کلید های ممکن در یک Map پیش از آن شناخته شده است - مثلا هنگام استفاده از یک Map پیکربندی. اگر این تعداد نسبتا کوچک باشد، باید به جای HashSet یا HashMap به طور منظم از EnumSet یا EnumMap استفاده کنید. به سادگی با نگاه کردن بهEnumMap.put () توضیح داده شده است: private transient Object[] vals; public V put(K key, V value) { // ... int index = key.ordinal(); vals[index] = maskNull(value); // ... } ماهیت این پیاده سازی این واقعیت است که ما یک آرایه از مقادیر نشان داده شده به جای یک جدول هش داریم. هنگام وارد کردن یک مقدار جدید، همه کاری که ما باید انجام دهیم برای یافتن ورودی Map از enum برای ترتیب ثابت آن است که توسط کامپایلر جاوا در هر نوع enum ایجاد می شود. اگر این یک Map پیکربندی Static است (یعنی تنها یک نمونه)، افزایش سرعت دسترسی به EnumMap کمک خواهد کرد که HashMap را به شدت بهبود بخشد، که ممکن است از حافظه heap کمی استفاده کند. Enum و EnumMap بسیار نزدیک هستند. هر زمان که از ساختارهای enum مثل کلید استفاده می کنید، در واقع ساختن این ساختارها را در نظر بگیرید و از آنها به عنوان کلید در EnumMap استفاده کنید. 9. Optimise your hashCode() and equals() methods : اگر شما نمیتوانید از EnumMapاستفاده کنید، دست کم متدهای hashCode()وequals() را بهینه کنید.(سعی کنید این دومتد را باهم پیاده سازی کنید.) یک متد خوبhashCode() ضروری است، زیرا باعث می شود که تماسهای بیشتری به نسبت برابر با مقدار بسیار پر هزینه جلوگیری شود، زیرا GC بیشتری را در هر نمونه از آنها تولید می کند. @Override public int hashCode() { // [#1938] This is a much more efficient hashCode() // implementation compared to that of standard // QueryParts return name.hashCode(); } @Override public boolean equals(Object that) { if (this == that) { return true; } // [#2144] Non-equality can be decided early, // without executing the rather expensive // implementation of AbstractQueryPart.equals() if (that instanceof AbstractTable) { if (StringUtils.equals(name, (((AbstractTable<?>) that).name))) { return super.equals(that); } return false; } return false; } 10. Think in sets, not in individual elements : متاسفانه، بسیاری از برنامه نویسان از نظر الگوریتم های ساده، محلی فکر می کنند. آنها گام به گام یک مشکل را حل می کنند، شاخه شاخه، حلقه با حلقه، متد و روش. این سبک اجرایی و / یا برنامه نویسی کاربردی است. در حالی که به طور فزاینده ای آسان است که "تصویر بزرگتر" را در حال حرکت از حالت ضروری به شیء گرا (همچنان ضروری) تا برنامه نویسی کارآمد، همه این سبک ها چیزی ندارند که فقط در SQL و R و زبان های مشابه وجود دارد: Declarative programming // Pre-Java 8 Set result = new HashSet(); for (Object candidate : someSet) if (someOtherSet.contains(candidate)) result.add(candidate); // Even Java 8 doesn't really help someSet.stream() .filter(someOtherSet::contains) .collect(Collectors.toSet()); برخی ممکن است استدلال کنند که برنامه نویسی کاربردی و جاوا 8 به شما کمک می کند تا ساده تر، الگوریتم های مختصر تر بنویسید. این لزوما درست نیست شما می توانید ضرورت Java 7 loop خود را به یک مجموعه کاربردی Java 8 Stream ترجمه کنید، اما هنوز همان الگوریتم را نوشته اید. و برای بهینه تر کردن برنامه های خود می توانید از ابزار قدرتمند JProfiler's که در این آدرس Java Profiler - JProfiler موجود می باشد استفاده نمایید.
  5. ادامه آموزش توابع کاربردی برای برنامه نویسی سوکت... تابع bind : int bind( SOCKET s, const struct sockaddr FAR *name, int namelen ); این تابع وظیفه پیوند دادن اطلاعات ارتباطی (مانند آدرس) را به سوکت تعریف شده دارد ودر برنامه سرور به کار می رود. آرگومان های این تابع به ترتیب زیر خواهد بود... آرگومان اول که متغیر نوع سوکت تعریف شده در برنامه است که با مقدار برگشتی تابع socket مقدار دهی شده است. آرگومان دوم آدرس محلی از حافظه است که متغیر ساختمان sockaddr_in در آنجا تعریف شده است (شرح این ساختمان در ادامه درج شده است.) آرگومان سوم هم اندازه متغیر ساختمان sockaddr_in است که می توانید با عملگر sizeof اندازه آن را بدست آورید. این تابع در صورت موفقیت مقدار صفر را بر می گرداند و در صورت عدم موفقیت SOCKET_ERROR را بر می گرداند. ساختمان داده ای sockAddr_in یک structure تعریف شده در هدر winsock.h است که محل نگه داری شماره پورت ارتباط و همچنین آدرس IP و دیگر اطلاعات است. struct sockaddr_in{ short sin_family, unsigned short sin_port, struct in_addr sin_addr, char sin_zero[8] }; عضوی به نام sin_family برای نگه داری نوع آدرس ارتباطی است که برای کاربرد های اینترنتی برابر ثابت AF_INET است. عضو sin_port مشخص کننده شماره پورت ارتباطی است. تابع تبدیل کننده htons(int portNumer) برای تبدیل عدد به نوع قابل فهم (BE1 to LE2) توسط ساختمان از تابع فوق استفاده می شود. و عضو sin_addr که خود یک ساختمان می باشد برای نگه داری آدرس IP که به صورت یک رشته کاراکتر مشخص می شود می باشد تابع تبدیل کننده inet_addr(char *ipaddress) برای تبدیل رشته کاراکتری که معرف آدرس IP است به نوع قابل فهم برای ساختمان داده از تابع فوق استفاده می کنیم. مثال کاربردی : sockaddr_in recSinIP; recSinIP.sin_family = AF_INET ;//set address family recSinIP.sin_port = htons(1362);//set port number recSinIP.sin_addr.S_un.s_addr = inet_addr("192.168.0.1"); نکته فنی : توجه داشته باشید که طبق تعاریف شبکه مقدار حداکثری تعریف پورت می تواند 65555 می باشد. که از این مقدار 1024 پورت اول توسط لایه های شبکه رزرو شده اند بنابراین شما نمی توانید از آنها استفاده نمایید. مانند پورت 80 که مختص به پروتکل HTTP می باشد. تابع listen : int listen( SOCKET s, int backlog ); تابع listen وظیفه گوش دادن به خط را در برنامه سرور به عهده دارد توجه داشته باشید که این تابع فقط در برنامه سرور کاربرد دارد. شرح آرگومان ها: آرگومان اول S که متغیر سوکت تعریف شده در برنامه می باشد. آرگومان دوم backlog هم تعداد صف های درخواستی است که به سیستم در یک زمان درخواست ارتباط داده اند و سیستم می تواند آنها را به حالت معلق نگه دارد این آرگومان می تواند برابر ثابت SOMAXCONN باشد. این تابع در صورت موفقیت صفر و درصورت بروز خطا ثابتی برابر با SOCKET_ERROR را برمی گرداند. تابع accept : SOCKET accept( SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen ); این تابع برای قبول درخواست اتصال بعد از تابع listen استفاده می شود. آرگومان های این تابع مانند تابع bind می باشد با این تفاوت که در آرگومان addr مشخصات ماشین متصل شده به سرور قرار می گیرد. آرگومان addrlen اندازه ساختمانی که این اطلاعات را نگهداری می کنند را مشخص می کند. این تابع در صورت موفقیت مقدار برگشتیش توصیفات مربوط به سوکت ماشین راه دور مورد نظر ماست و در صورت بروز خطا ثابتی به نام INVALID_SOCKET را بر می گرداند. تابع connect : int connect( SOCKET s, const struct sockaddr FAR *name, int namelen ); تابع connect وظیفه برقراری ارتباط را با برنامه سرور بر عهده دارد و آرگومان های آن به شرح زیر می باشد: آرگومان اول s که از نوع سوکت می باشد وهمان مقدار برگشتی تابع socket می باشد. آرگومان دوم هم که از نوع sockAddr_in می باشد. و آرگومان آخر تابع connect یعنی namelen اندازه ساختمان داده sockaddr_in است که می توان به جا مقدار آن نوشت : sizeof(sockaddr_in) این تابع در صورت موفقیت مقدار صفر و در صورت بروز خطا ثابتی برابر با SOCKET_ERROR را بر می گرداند. نکته فنی : همانطور که میدانید در کامپیوتر های امروزی کلمات در حافظه به صورت (LE(Little Endian ذخیره می شوند، یعنی بایت کم ارزش تر در خانه با شماره کوچکتر ذخیره می شود و بایت با ارزشتر در خانه با شماره بزرگتر ذخیره می شود. مثلا برای عدد هگز 3578H بایت کم ارزشتر برابر 78 وبایت پرارزشتر برابر عدد 35 است وترتیب قرار گرفتن آنها در حافظه به صورت زیر می باشد: خانه 89:35 خانه 89:34 خانه 89:33 خانه 89:32 همانطور که مشاهده میکنید بایت کم ارزشتر در آدرس 89:33 ذخیره شده و بایت با ارزشتر در خانه 89:34 ذخیره شده است کامپیوترهای معمول بدین صورت کلمات را در حافظه ذخیره میکنند اما در پشته TCP/IP به صورت عکس عمل می شوند یعنی از نوع (BE(Big Endian پشتیبانی می شود به بیان دقیق تر باید ترتیب بایت ها در حافظه درست باشد یعنی بایت با ارزشتر در آدرس کوچکتر و بایت کم ارزشتر در آدرس بزرگترذخیره شود مثلا برای عدد 3578H مانند شکل زیر عمل می شود: خانه 89:32 خانه 89:33 خانه 89:34 خانه 89:35 البته باید توجه داشته باشید که فقط ما باید ورودی های هدر TCP/IP را به نوع (BE(Big Endian تبدیل کنیم یعنی آدرس IP و شماره پورت وکلا اطلاعاتی که تحت شبکه ارسال می شوند. دیگر ثوابت به طور خودکار در تمامی کامپیوترها به صورت صحیح قرار دارند و دیگری نیازی به تنظیم ما ندارند. //برمی گرداند BE این تابع آرگومان خود را که یک عدد دوبایتی است به حالت u_short htons( u_short hostshort ); //برمی گرداند BE این تابع آرگومان خود را که یک عدد چهار بایتی است را به حالت u_long htonl( u_long hostlong ); //برمی گرداند LE این تابع آرگومان خود را که یک عدد دوبایتی است به حالت u_short ntohs( u_short netshort ); //برمی گرداند LE این تابع آرگومان خود را که یک عدد چهار بایتی است را به حالت u_long ntohl( u_long netlong ); //که معرف آدرس آی پی است را دریافت میکند ویک عدد چهار بایتی (a.b.c.d)این تابع یک رشته کاراکتر //بر می گرداند در صورتی که آدرس آی پی نامعتبر باشد یا تابع عملیات خود را با موقیت انجام BE از نوع //توسط تابع برگردانده می شود INADDR_NONE ندهد ثابت unsigned long int inet_addr( const char FAR *cp ) همچنان ادامه خواهد داشت...
  6. فرهاد شیری

    با سلام دوست عزیز! بحث مهندسی نرم افزار و تولید یک نرم افزار مستقل از پلت فرم کدنویسی هست. بنابراین اگر پروژه ای که می خواهید شروع کنید را طبق الگوهای مهندسی نرم افزار طراحی کنید مشکلی در ایجاد کلاسها نخواهید داشت. وقتی شما سناریو پروژه را به درستی تعریف کنید و طراحی درستی از برنامه و اهداف برنامه به وجود بیاورید مطمئن باشید که برای نوشتن کلاسها و استفاده از کلاسهای هر پلت فرم هم که کار کنید مشکلی نخواهید داشت. بهتر برای تحلیل یک پروژه نرم افزاری ابتدا... 1- تهیه سناریو برنامه که شامل RFP ها و ... 2- تهیه وایر فریم ها 3- ایجاد نمودارهای کاربردی در زبان های مدل سازی ( CRC Class , Diagram Class ,Data Flow Diagram(DFD) ,Activity Diagram,State Diagram) البته توجه داشته باشید که فقط مدل هایی که واقعا کاربردی هستند و براساس تجربه خودم عرض کردم. 4- مدل سازی تجاری(تمامی فعالیت هایی که در اون بخشی که شما دارید برای اون بخش نرم افزار تهیه میکنید را باید شناسایی کنید) 5- مدل سازی داده (در صورتی که از پایگاه داده استفاده میکنید نرمال سازی حداقل تا 3 سطح ویا دی نرمال کردن پایگاه داده تهیه مدل های Table Structure , Relations , Primary Key, Foreign key,...) 6- مدل سازی فرآیند (پردازش ها روال های کاری برای اضافه کردن و تغییر و حذف و بازیابی اشیای داده ...) ماژولار کردن نرم افزار (تقسیم به بخش های کوچکتر) 7- استخراج الگوهای طراحی نرم افزار (MVC , MVVP , MVP) و شناسایی کتابخانه ها ویا کلاسهای کاربردی در جهت تسهیل ایجاد نرم افزار... 8- شناسایی پلت فرم و زبان برنامه نویسی و تهیه خروجی کلاسها و توابع از روی مدل های ایجاد شده. 9- تولید کدها و تست های واحد Unit Test 10- تولید و یا اجرای اتوماتیک تست های نرم افزاری (Performance Test , Smoke Test , White Test,...) 11- ایجاد خروجی باینری پروژه نسخه بتا ... امیدوارم مفید باشه البته خیلی کلی عرض کردم به هر حال برای تولید یک برنامه کاربردی حتما لازمه که تمام مسائل مهندسی رو به جلو در نرم افزار رعایت بشه.!
  7. فرهاد شیری

    من که هیچوقت ازش استفاده نکردم چون کلا با qmake و cmake خیلی راحتترم. برادر کامبیز! اصلا فلسفه وجودی این Qbs چی بود؟
  8. با سلام هدف من از تهیه این آموزش شناخت کلی درباره (Socket Programming) که بسیار وسیع هست، والبته برای خیلی از برنامه نویسها هم همیشه جذاب بوده که بتوانند برنامه های تحت شبکه بنویسند بوده است. و از آنجاییکه با فراگیری برنامه نویسی سوکت در زبان C قادر خواهید بود، برنامه هایی در زمینه های بسیار تخصصی مانند (Intrusion Detect system) سیستم های تست نفوذ، ابزارهای (sniff) تحت نظرقرار دادن پکت ها، تا برنامه های ساده ای مانند چت و نمایش فیلم های آنلاین و خرید های مجازی و ... را انجام دهید. البته ما دراین آموزش سعی بر آن خواهیم داشت که بیشتر به نکات کاربردی درباره سوکت، که اغلب خود من از آنها در پروژه هایم استفاده کرده ام اشاره داشته باشیم. سوکت (Socket) چیست؟ با یک بیان ساده می توان گفت که سوکت به ترتیب یک آدرس ماشین IP ویک شماره درگاه Port گفته می شود. در برقراری ارتباط بین کامپیوترها در یک شبکه دوچیز بسیار مهم است. 1- آدرس ماشینی که می خواهیم اطلاعاتی از آن بگیریم ویا به آن ارسال کنیم. 2- برنامه ای از آن ماشین که در خواست اطلاعات کرده یا اینکه می خواهیم اطلاعاتی از آن برنامه کسب کنیم این دو یعنی آدرس ماشین وشماره برنامه به وسیله سوکت در شبکه مشخص می شوند. WinSock چیست؟ Winsock یا Windows Socket یک رویه (Interface) برنامه نویسی است که در غالب یک DLL در سیستم عامل ویندوز برای برنامه نویسی شبکه و ساخت برنامه هایی که بتوانند با شبکه محاوره داشته باشند معرفی شده است. ارتباط مابین دوکامپیوتر می تواند به یکی از دوصورت زیر باشد: - اتصال گرا (Connection Oriented) - غیر اتصال گرا (Connection Less) در سیستم اتصال گرا ابتدا درخواست اتصال ارسال شده و درصورت موافقت طرف مقابل ارتباط برقرار می شود.به این تکنیک Data Stream نیز گفته می شود. اما در سیستم غیر اتصال گرا بدون نیاز به موافقت طرف مقابل بسته ها ارسال می شوند به این تکنیک Data Gram نیز می گویند. TCP/UDP : در پشته پروتکلی TCP/IP دونوع ارتباط می توان با کامپیوتر دور ایجاد کرد: - اتصال به کامپیوتر راه دور به وسیله سوکت Data Stream. - اتصال به کامپیوتر راه دور به وسیله سوکت Data Gram. به طورخلاصه به نوع ارتباط اول (اتصال گرا) ارتباط از نوع TCP گفته می شود. واگر نوع برقراری ارتباط به حالت (غیر اتصال گرا ) باشد به آن UDP گفته می شود. دوستان بهتره هست قبلا حتما مدل مرجع OSI برای شناخت بهتر لایه های شبکه را مطالعه نمایید. به علت مباحث تکنیکی و کمی هم پیچیده مدل OSI ما در این آموزش وارد جزئیات نخواهیم شد. تحقیق درباره آن را به خودتون واگذار میکنم. معرفی توابع مهم مورد استفاده در برنامه نویسی TCPIP با زبان C کتابخانه کار با سوکت های در زبان C می تواند از سیستم عاملی به سیستم عاملی دیگر متفاوت باشد. همینطور از سخت افزاری به سخت افزاری دیگر به عنوان مثال برای برنامه نویسی شبکه در سیستم عامل ویندوز ما از هدر فایل winsock2.h استفاده می کنیم که خود نگارشهای مختلفی دارد وبرای برنامه نویسی شبکه در سیستم عامل های خانواده NIX* از هدر فایل sys/socket.h , sys/type.h و هدرهای دیگر استفاده می کنیم که البته می توان با اقدامی هوشمندانه توسط راهنمای کامپایلر نوع سیستم عامل را تشخیص داد وبعد هدر های مربوط به هر سیستم عامل را مورد استفاده قرارداد. البته باید عرض کنم که توابع مورد استفاده در همه انواع هدرها یکسان می باشند، مگر در معدود مواردی که هر کجا احساس نیاز شود ذکر خواهند شد. شرح توابع مهم موجود در هدر فایل winsock2.h int WSAStartup( WORD wVersionRequested , LPWSADATA lpWSAData ); این تابع برای آماده سازی و بار گذاری اولیه سیستم عامل برای اجرای برنامه تحت شبکه می باشد. آرگومان های آن عبارتند از : wVersionRequested شماره نگارش هدر winsock.h است که برای تبدیل این شماره به نوع WORD می توان از ماکرو makeword استفاده کرد. نکته فنی : به هر 4 بیت یک NIBBLE گفته می شود. وبه هر 8 بیت یک BYTE گفته می شود. وبه هر 16 بیت یا دو بایت یک WORD گفته می شود. به عنوان مثال : WORD wVersionRequested=makeword(2,0); winsock1.1.h و برای نگارش WORD wVersionRequested=makeword(2,1); و آرگومان دوم یک متغیر از نوع ساختمان داده ای WSADATA می باشد که در هدر winsock تعریف شده است. اعضای این ساختمان و نحوه تعریف آن به این صورت است: typedef struct WSAData{ WORD wVersion; WORD wHighVersion; char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYS_STATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR* lpVendorInfo; } WSADATA , *LPWSADATA; مثال کاربرد : WSADATA wsaData; WORD wVersionRequested=makeword(2,0); WSAStatrtup(wVersionRequested,wsaData); این تابع در صورت موفقیت مقدار صفر را بر می گرداند و در صورت شکست کد خطای رخ داده را بر می گرداند. int WSACleanup(void); از این تابع برای اتمام بارگذاری مربوط به شکست سیستم عامل استفاده می شود. این تابع در صورت موفقیت مقدار صفر و در صورت بروز خطا ثابتی برابر با SOCKET_ERROR را برمی گرداند. تابع socket : SOCKET socket( int af, int type, int protocol ); از تابع فوق برای تعریف وایجاد یک پورت استفاده می کنیم .و مقدار برگشتی آن توصیف کننده پورت مورد نظر است آرگومانهای تابع به ترتیب از این قرار هستند: af - مشخص کننده نوع آدرس است که برای کاربری اینترنت برابر ثابت AF_INET است برای کنترل سوکت ها در یونیکس برابر ثابت AF_UNIX است و مقادیر دیگر... type - مشخص کننده نوع ارتباطها می باشد که برای ارتباط TCP ثابت SOCK_STREAM و برای یک ارتباط UDP برابر SOCK_DGRAM است. protocol - هم نماینگر نوع پروتکل انتخابی ماست برای یک ارتباط TCP برابر با ثابت IPPROTO_TCP یا مقدار عددی 0 وبرای UDP مقدار عددی 1 یا ثابت IPPROTO_UDP می باشد. این تابع در صورت موفقیت مقدار برگشتی اش توصیفات مربوط به سوکت مورد نظر ماست و در صورت بروز خطا ثابتی به نام INVALID_SOCKET را بر می گرداند. ادامه دارد...
  9. دوست عزیز! الگوریتم تبدیل تاریخ میلادی به شمسی معمولا به یک روش انجام می شود.چندتا فرمول ریاضی ساده و چند تا شرط برای (روز و ماه و سال و کبیسه و...) منظورتون از الگوریتم پیشنهادی چی؟ بهتر سورس کدتون را قرار بدید تا بهتر پاسخ داده بشه!
  10. فرهاد شیری

    بله می توانید در QML هم استفاده کنید در صورتی که علاقه مند به مباحث طراحی در کیوت و QML هستید پیشنهاد میکنم حتما ویرایش دوم کتاب آقای اسدزاده (کتاب آموزش پیشرفته ++C همراه Qt (پیشرفته) - کتاب‌ها و مقالات - جامعه‌ی برنامه‌نویسان مُدرن ایران) را مطالع کنید.
  11. جویبار(Stream) در جاوای 8 شاید به جرات بتوان گفت که قوی ترین امکان که به کتابخانه های جاوا اضافه شده استفاده از جویبارهاست(Stream) البته هیچ ربطی به جریان های ورودی و خروجی (فایل و مانیتور و...) در زبان جاوا ویا حتی ++C نداره.! در حقیقت جویبارها امکان ایجاد عملیاتهایی بر رروی داده های یک ظرف (Container) را در یک سیکل دستوری به واقعیت تبدیل کرده اند. اگر با زبان سی شارپ آشنایی داشته باشید می توان گفت تکنیک جویبار ها بسیار شبیه تکنولوژی Linq می باشد.(البته Linq بسیار ساختارمند تر و قدرتمند تر هست ولی در ایجاد هر دو تکنیک جویبار و Linq تقریبا یک تفکر حاکم بوده است. سعی میکنم با ذکر مثالهای کاربردی درباره تکنیک های جویبار در جاوا 8 آشنایی بیشتری برای شما فراهم کنم برای اینکه بخواهید یه مقدار ماکزیمم رو توی یه لیست پیوندی پیدا کنید چند خط کد باید بنویسیم، کاری به الگوریتم پیاده سازی ندارم (جستجوی خطی و یا باینری و یا ادغامی ویا سریع ...) میتونه هرالگوریتمی باشه.! ولی مطمئنا کدنویسی زیادی میخواد! ولی با جویبار Stream چطوری میتونیم انجام اش بدیم که همزمان هم بازدهی بهتری داشته باشیم وهم کد نویسی کمتر؟! public <E extends Comparable<? super E>> E max(List<? extends E> list, boolean sorted) { Stream<? extends E> stream = list.stream(); Optional<E> optional = stream .sorted() .collect(Collectors.maxBy((o1, o2) -> sorted ? o1.compareTo(o2) == 1 ? 0 : 1 : o1.compareTo(o2))); return optional.isPresent() ? optional.get() : list.get(0) ; توضیح کد نمونه : ابتدا یک Stream برای آبجکت List ایجاد کردم. 1- بعد با اینترفیس Optional ابتدا جویبار را با آبجکت Comparable پیش فرض که در تعریف متد پیاده سازی شده مرتب کردم. 2- با متد Collect از جویبار یه خروجی لیست جدید می گیریم و با استفاده از کلاس Collectors متد استاتیک MaxBy لیست جدید را داده کاوی می کنیم (با یک عبارت لاندا که از کلاس Comparator آبجکتها رو کنترل میکنم) و در مرحله بعد با متد isPersent اینترفیس Optional چک می کنیم که آیا لیست جدید تشکیل شده است یا خیر اگر لیست ایجاد نشود، اولین عضو لیست هم را پاس میدم فقط تو استفاده از Stream باید توجه داشته باشید برخی از متدهایش پایانی یعنی void هستن مثل foreach و یا همین collect برخی از متدها هم میانی با خروجی هستن مثل متد Filter اگر هم بخوام خیلی ساده بگم یعنی بعد از هر عملیات میانی میتونیم از متد های دیگه استریم استفاده کنیم و با الطبع بعد از هر عملیات پایانی هم نمی تونیم چون الگوی ساخت کلاس استریم Builder هست پس هر عملیات میانی همون شی جاری استریم هستش. حالا در جاوای قبل از 8 به این روش می نوشتیم... @Override public <C extends Comparable<? super C>> C max(List<? extends C> list,C keyCompare) { Iterator<? extends C> iterator = list.iterator(); C result = keyCompare; while (iterator.hasNext()) { C t = iterator.next(); if (t.compareTo(result) > 0) { result = t; } } return result; }
  12. فرهاد شیری

    کلاس Single Tone ژنریک با استفاده از اشاره گرهای هوشمند برای ساخت آبجکتی از یک کلاس با یک نمونه واحد برای صرفه جویی در حافظه مصرفی #ifndef SINGLETON_H #define SINGLETON_H #include <memory> namespace BP { template<typename CL> class SingleTone { protected: SingleTone() = default; // defualt ctor virtual inline ~SingleTone(){ delete instance; } private: static CL* instance; SingleTone(const SingleTone&) = delete; //copy ctor SingleTone(SingleTone&&) = delete ; //move ctor SingleTone& operator=(const SingleTone&) =delete ; // copy oprator assignment SingleTone& operator=(SingleTone&&) =delete ; // move oprator assignment static void destory(CL* my){ delete my ; instance = NULL; } public: std::unique_ptr<CL , decltype(&destory)> factory(){ //lazy instation if(instance == NULL){ instance = new CL(); } return std::unique_ptr<CL , decltype(&destory)>(instance , &destory); } }; template<typename CL> CL* SingleTone<CL>::instance = NULL; } #endif // SINGLETON_H ونحوه استفاده از کلاس فوق من کلاسی دارم برای ارتباط با پایگاه داده به نام DBProvider که در این کلاس متدی به نام OpenConnection را صدا زدم. توجه کنید که هر کلاسی که بخواهید را می توانید به حالت single tone ایجاد نمایید. روش اول فراخوانی db = SingleTone<DBProvider>::factory ()->OpenConnection () روش دوم فراخوانی db = (*SingleTone<DBProvider>::factory ()).OpenConnection (); فقط توجه داشته باشید که آبجکتهایی که single tone هستند یک اشاره گر واحد دارند بنابراین در کل برنامه یکسان خواهند بود.
  13. فرهاد شیری

    دوست عزیز! عرض کردم اصولا تمامی پنجره ها در برنامه های تحت ویندوز از کلاسهای پایه ویندوز ارث بری دارند ولی شما می توانید استایل های خودتون را هم طراحی کنید و در زمان نمایش پنجره بارگذاری کنید و هرکدام از محیط های طراحی نرم افزار های ویندوزی این کار را به شکلی خاص انجام میدن. در ویژوال سی با MFC در سی شارپ با XAML با کتابخانه WPF در جاوا FXML با کتابخانه JAVAFX در کیوت UI فایل با CSS,HTML ویا QML بنابراین طراحی استایل های لینوکسی در پنجره های ویندوزی تقریبا نشدنی است! مگر با استفاده از طراحی های گرافیکی جداگانه برای پنجره های ویندوزی در زمان نمایش برنامه که البته این روش هم سربار زیادی خواهد داشت با استفاده از این کلاس می توانید استایل های پنجره ها را از قبل در فایل هایی به فرمت CSS آماده کنید و در زمان اجرا این فایل ها را با این کلاس بارگذاری کنید. این نکته را هم عرض کنم همین امکان فوق العاده فریم وورک کیوت (استفاده از CSS) در ویژوال سی آرزوی دست نیافتنی هست! به این علت که در محیط ویژوال سی شما می توانید از قالب های استاندارد ویندوز و تم های استاندارد آفیس برای استایل برنامه استفاده کنید.
  14. فرهاد شیری

    من هم موافقم تم های لینوکسی علی الخصوص اینترفیس برنامه ها در دسکتاپ KDE فوق العاده است. ولی برای همین دسکتاپ های لینوکسی انقدر کار شده که ویندوز کو بهش برسه! بنابراین با اینکه نحوه بار گذاری پنجره ها در ویندوز در برنامه های کیوت مستقل از کتابخانه هایی مثل MFC مایکروسافت هست ولی بازهم از کلاسهای پایه ویندوز ارث بری خواهند داشت به همین علت شما نمی توانید GUI هایی مانند لینوکس استفاده کنید. البته با CSS در کیوت می تونید برنامه هایی با ظاهر بسیار زیبا درست کنید در ویندوز که به مراتب کاربر پسند تر از کلاسهای ویژوال سی مایکروسافت هستند. یک نمونه از برنامه های خودم که کلا با استفاده از CSS کار شده والبته ویجت کلاس های کیوت
  15. فرهاد شیری

    Typedef qint64 : نوع int را که یک عدد صحیح 4 بایتی با long long افزایش میده به یک داده 64 بیتی که در سیستم عامل های 64 بیتی که توسط کیوت پشتیبانی میشه تعریف میکنه.! و اینکه چه مواردی را پشتیبانی میکنه بستگی به کاربرد شماداره! یکی از کاربرد های مهم پر استفاده تبدیل یک بایت رشته ای به یک نوع داده ای عدد صحیح اصلاح شده از نوع qint64 هست. inline qint64 GetInteger64(QLineEdit* lineEdit){ qint64 nValue = 0; bool ok; nValue = lineEdit->text().toLongLong(&ok,10); return nValue; } اگر بخواهید اعداد صحیح 64 بیتی امضا شده را به صورت مستقل از پلت فرم هم قرار بدید می تونید از ماکرو زیر هم استفاده کنید qint64 value = Q_INT64_C(932838457459459);
×