كيفيه إرسال بيانات خارج النطاق متعددة البايت باستخدام Winsock

الملخص

في بعض الأحيان يجب عليك إرسال البيانات العاجلة الخاصة بالخارج النطاق إلى مستقبلاتك. المستلمون هم اي مستخدمين أو اي تطبيقات تتلقي البيانات. تريد معامله بيانات OOB هذه كبيانات ذات اولويه اعلي من اي بيانات عادية يمكنك إرسالها. إذا كانت بيانات OOB التي تريد إرسالها عبارة عن بايت واحد ، فيمكنك استخدام الدالة select للبحث عن بيانات oob. يمكنك استخدام الدالة التي تم تلقيها لقراءه البيانات. علي الرغم من ذلك ، في بروتوكول التحكم بالإرسال (TCP) ، تكون كتله بيانات OOB عبارة عن بايت واحد دائما. ولذلك ، إذا أرسلت بيانات OOB متعددة البايت ، سيتم استرداد البايت الأخير فقط من بيانات OOB. تتم معامله البيانات المتبقية كالبيانات العادية. تستخدم هذه المقالة الرمز النموذجي لوصف كيفيه إرسال بيانات OOB متعددة البايت باستخدام Microsoft Windows ماخذ التوصيل (Winsock).

في هذه المهمة

مقدمة

تصف هذه المقالة كيفيه إرسال البيانات من عده وحدات بايت (أحرف) باستخدام Winsock. يتم إنشاء التطبيقات النموذجية في Microsoft Visual c + +. لان اليه OOB هذه ليست معتمده مباشره علي مستوي ماخذ التوصيل في Microsoft Windows ، يجب تطبيق اليه OOB هذه علي مستوي التطبيق. هذه البيانات غير صحيحه في OOB. في هذا التطبيق النموذجي ، يمكنك إنشاء ماخذ توصيل علي الجهاز العميل ، والمعروف أيضا باسم المرسل ، لإرسال بيانات OOB والبيانات العادية. علي جانب الخادم ، المعروف أيضا باسم جانب المستلم ، يمكنك استخدام ماخذ توصيل لمعالجه البيانات في مؤشري ترابط. مؤشر ترابط واحد لبيانات OOB. يتم تنفيذ مؤشر الترابط الآخر للبيانات العادية. لمحاكاة اليه OOB ، يجب مزامنة مؤشري الترابط هذين. تاكد من ان مؤشر الترابط الذي يعالج بيانات OOB لديه اولويه اعلي من مؤشر الترابط الذي يعالج البيانات العادية.ملاحظة يتم إصدار Acrobat Reader من قِبل شركة Adobe Systems Inc.‎. يوضح هذا التطبيق النموذجي طريقه واحده لإرسال بيانات OOB متعددة البايت. قد تحتاج إلى مراجعه التعليمات البرمجية لجعل التعليمات البرمجية تعمل في بيئتك.عودة إلى الأعلى

إنشاء تطبيق عميل

  1. إنشاء تطبيق عميل. في تطبيق العميل هذا ، تصف التعليمات البرمجية النموذجية التالية كيفيه إنشاء ماخذ توصيل:

    SOCKET myOOBSocket = INVALID_SOCKET;SOCKET myNormalSocket = INVALID_SOCKET;myOOBSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);myNormalSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    يتم استخدام متغير ميوبسوكيت لإرسال بيانات OOB. يتم استخدام المتغير مينورمالسوكيت لإرسال البيانات العادية.

  2. نظرا لان البيانات التي يرسلها المتغير ميوبسوكيت ليست صحيحه في البيانات ، يجب ان تكون لديك طريقه لاعلام الخادم بنوع البيانات التي يفترض إرسال ماخذ التوصيل لها قبل البدء في إرسال البيانات. تصف التعليمات البرمجية النموذجية التالية كيفيه إرسال حرف اولي لاعلام الخادم بنوع البيانات التي سيتم إرسالها. استخدم "U" لبيانات OOB واستخدم "N" للبيانات العادية.

    int nErr, nSize;nErr = connect(myNormalSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));//Look for a potential error here.//"remoteIp" is the remote address.nSize = send(myNormalSocket, "N",1, 0);//Look for a potential error here.nErr = connect(myOOBSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));//Look for a potential error here.nSize = send(myOOBSocket,"U",1, 0);//Look for a potential error here.
  3. تصف التعليمات البرمجية النموذجية التالية كيفيه جعل تطبيق العميل يقوم بمراقبه الإدخال من المستخدم. يرسل تطبيق العميل الأحرف الكبيرة كبيانات OOB. تكرار كل حرف إدخال لإنشاء سلسله متعددة البايت.

    for (;;) {int ch = _getch();_putch( ch );if (ch=='.') {shutdown(myOOBSocket, 2);        shutdown(myNormalSocket,2);break;}        char buf[10];        memset(buf, ch, sizeof(buf));        if (isupper(ch)) {nSize = send(myOOBSocket, buf, sizeof(buf), 0);//Do not use the MSG_OOB flag. Send it as normal data.} else {nSize = send(myNormalSocket, buf, sizeof(buf), 0);}...}

عرض التعليمات البرمجية النموذجية لتطبيق العميل ، ميكلينت العودة إلى الأعلى

إنشاء تطبيق خادم

  1. علي جانب الخادم ، تصف التعليمات البرمجية النموذجية التالية كيفيه إنشاء ماخذ التوصيل المصغي لمراقبه المنفذ الذي يتم استخدامه للاتصال:

    int nErr;SOCKET myListener = INVALID_SOCKET;myListener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//Look for a potential return error here.nErr = bind(myListener,(SOCKADDR *)&localIp,sizeof(localIp));//Look for a potential return error here.//"localIp" is the local address of the server.nErr = listen(myListener, 5);//Look for a potential return error here.
  2. تصف التعليمات البرمجية النموذجية التالية كيفيه الاتصال بالدالة " قبول " لجعل ماخذ المصغي ينتظر محاولات الاتصال الوارد:

    for (;;) {struct sockaddr_in remoteIp;SOCKET remoteSocket = INVALID_SOCKET;int nAddrLen = sizeof(SOCKADDR);remoteSocket = accept(myListener, (SOCKADDR *)(&remoteIp), &nAddrLen);//"remoteIp" is a pointer to a buffer that receives //the address of the connecting entity.BYTE buffer[1+1];int recv_len=recv(remoteSocket,(char *)&buffer,1,0);//This supposes that the client sockets will send//"U" or "N" as the initial character.    buffer[recv_len] = '\0';if(strcmp((char *)buffer,"U")==0)hThread=CreateThread(0,0,OOBHandler,(LPVOID)remoteSocket, 0, &dwThreadId);//Create a new thread to process incoming OOB data. "OOBHandler" is a //pointer to the OOB data handler. else if(strcmp((char *)buffer,"N")==0)hThread=CreateThread(0,0,NormalHandler,(LPVOID)remoteSocket, 0, &dwThreadId);//Create a new thread to process incoming normal data. "NormalHandler" is //a pointer to the normal data handler....}
  3. لمحاكاة اليه OOB ، يجب مزامنة مؤشري الترابط هذين. في هذا التطبيق النموذجي ، استخدم عنصر حدث عمومي للقيام بذلك. ضع العبارة التالية في اعلي الملف.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. أنشئ معالج OOB الذي يتم تنفيذه بواسطة مؤشر ترابط منفصل. في هذا المعالج ، يمكنك استخدام الدالة select للكشف عن وقت وصول البيانات. عند وصول البيانات ، اتبع الخطوات التالية:

    1. اتصل بالدالة ريسيتيفينت لتعيين عنصر الحدث هريكفيفينت إلى الحالة غير المحددة.

      ResetEvent(hRecvEvent);

      هذا يحظر معالج البيانات العادية الذي يتم تنفيذه في مؤشر ترابط آخر.

    2. اتصل بالدالة ريفك لقراءه البيانات.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. لأنه من الممكن ان يتم إرسال المزيد من البيانات من المخزن المؤقت ، يمكنك الاتصال بالدالة تلقي مره أخرى ، مع علامة الMSG_PEEK ، لتحديد ما إذا كانت اي بيانات متوفرة علي السلك.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer)-1,MSG_PEEK);

      استخدم أحدي الطريقتين التاليتين ، استنادا إلى ما إذا كانت هناك بيانات معلقه للقراءة ام لا:

      • إذا لم يكن هناك اي بيانات معلقا للقراءة ، فقم باستدعاء الدالة سيتيفينت لتعيين كائن الحدث المحدد إلى الحالة الاشاره.

        SetEvent(hRecvEvent);

        عند القيام بذلك ، يمكن استئناف مؤشر ترابط معالج البيانات العادي. ينتظر مؤشر ترابط معالج البيانات العادي لعنصر الحدث هريكفيفينت قبل استئناف مؤشر ترابط معالج البيانات العادي.

      • إذا كانت البيانات لا تزال معلقه لتتم قراءتها ، فاتصل بالدالة تلقي مره أخرى لقراءه البيانات المتبقية. بعد ذلك ، ابحث مره أخرى عن البيانات المعلقة.

    كرر الخطوات من 4 إلى 4a حتى تتم قراءه كل البيانات المعلقة.

  5. أنشئ معالج البيانات العادية. يتشابه هذا المعالج مع معالج بيانات OOB باستثناء ان معالج البيانات العادي يقوم باستدعاء الدالة وايتفورسينجليوبجيكت عند اكتشاف معالج البيانات العادي انه قد وصلت البيانات.

    WaitForSingleObject(hRecvEvent,INFINITE);//You can set the interval parameter to a specific value if you do not want  //the normal data handler to wait for the OOB handler indefinitely when OOB data arrives continuously.

عرض التعليمات البرمجية النموذجية لتطبيق الخادم ، ميسيرفير العودة إلى الأعلى

عرض التعليمات البرمجية النموذجية لتطبيق العميل ، ميكلينت

ملاحظة يتم إصدار Acrobat Reader من قِبل شركة Adobe Systems Inc.‎. يجب ان تقوم بتضمين مرجع إلى ملف مكتبه Winsock ، Ws2_32 ، لجعل التحويل البرمجي للتعليمات البرمجية.

#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <assert.h>#include <winsock.h>main(int argc, char *argv[]){int nErr, nSize;WSADATA wsaData;SOCKET myOOBSocket = INVALID_SOCKET;SOCKET myNormalSocket = INVALID_SOCKET;unsigned short nPort; // Listen for the port number.struct sockaddr_in remoteIp;if (argc!=3){printf("TcpDemoC <RemoteIp> <Port>\n");return 0;}// The Init Socket API.nErr = WSAStartup(MAKEWORD(1,1),&wsaData);assert(nErr==0);nPort = (unsigned short)atol(argv[2]);myOOBSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);assert(myOOBSocket!=INVALID_SOCKET);myNormalSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);assert(myNormalSocket!=INVALID_SOCKET);// Connect to the remote address.remoteIp.sin_family = AF_INET;remoteIp.sin_port = htons(nPort);;remoteIp.sin_addr.S_un.S_addr = inet_addr(argv[1]);nErr = connect(myOOBSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));if (nErr == SOCKET_ERROR) {printf("Connect failed because of %lX\n",  WSAGetLastError());goto Cleanup;}nSize = send(myOOBSocket,"U",1, 0);if (nSize == SOCKET_ERROR) {printf("Send failed because of %lX\n", WSAGetLastError());        goto Cleanup;}    nErr = connect(myNormalSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));if (nErr == SOCKET_ERROR) {int error = WSAGetLastError();printf("Connect failed because of %lX\n", error);goto Cleanup;}    nSize = send(myNormalSocket, "N",1, 0);if (nSize == SOCKET_ERROR) {printf("Send failed because of %lX\n", WSAGetLastError());goto Cleanup;}printf("Read for input:\n");for (;;) {int ch = _getch();_putch( ch );if (ch=='.') {shutdown(myOOBSocket, 2);shutdown(myNormalSocket,2);break;}char buf[10];memset(buf, ch, sizeof(buf));if (isupper(ch)) {nSize = send(myOOBSocket, buf, sizeof(buf), 0);}else{nSize = send(myNormalSocket, buf, sizeof(buf), 0);}if (nSize == SOCKET_ERROR) {printf("Send failed because of %lX\n", WSAGetLastError());break;}}Sleep(1000);Cleanup:if (myOOBSocket!=INVALID_SOCKET)closesocket(myOOBSocket);if (myNormalSocket!=INVALID_SOCKET)closesocket(myNormalSocket);WSACleanup();return 0;}

عودة إلى الأعلى

عرض التعليمات البرمجية النموذجية لتطبيق الخادم ، ميسيرفير

ملاحظة يتم إصدار Acrobat Reader من قِبل شركة Adobe Systems Inc.‎. يجب ان تقوم بتضمين مرجع إلى ملف مكتبه Winsock ، Ws2_32 ، لجعل التحويل البرمجي للتعليمات البرمجية.

#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <winsock.h>#include <assert.h>// Usage: myserver <port>HANDLE hRecvEvent; DWORD WINAPI OOBHandler(LPVOID lpParam){int nErr, nRecv_len;BYTE buffer[10 + 1];BOOL bClosing=FALSE;fd_set fdread;SOCKET remoteSocket=(SOCKET)lpParam;unsigned long ul=1;int nRet = ioctlsocket(remoteSocket, FIONBIO, &ul);if(SOCKET_ERROR==nRet){printf("Socket() failed: %d\n", WSAGetLastError());return 1;}printf("Waiting");for (int i=0; i<10; i++) {printf(".");Sleep(1000);}printf("The OOB handler is ready!\n");while (!bClosing){//Always clear the set before you call the select method.FD_ZERO(&fdread);//Add sockets to the sets.FD_SET(remoteSocket, &fdread);nErr=select(0,&fdread,0,0,0);if(nErr==SOCKET_ERROR){printf("Select() failed: %d\n",WSAGetLastError());return 1;}if(FD_ISSET(remoteSocket,&fdread)){ResetEvent(hRecvEvent);while(1){nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);                    if(nRecv_len==0){bClosing=TRUE;printf("The connection is closed!\n");break;}buffer[nRecv_len] = '\0';printf("[OOB]: %s\n", buffer);                    nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer)-1,MSG_PEEK);if (nRecv_len==SOCKET_ERROR) {if(WSAGetLastError()==WSAEWOULDBLOCK)break;elseprintf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());}}SetEvent(hRecvEvent);} }return 0;}DWORD WINAPI NormalHandler(LPVOID lpParam){int nErr,nRecv_len;BYTE buffer[10 + 1];fd_set fdread;SOCKET remoteSocket=(SOCKET)lpParam;printf("Waiting");for (int i=0; i<10; i++) {        printf("*");Sleep(1000);}printf("Normal handler ready!\n");while(1) {//Always clear the set before you call the select method.FD_ZERO(&fdread);//Add sockets to the sets.FD_SET(remoteSocket, &fdread);nErr=select(0,&fdread,0,0,0);if(nErr==SOCKET_ERROR){printf("Select() failed: %d\n",WSAGetLastError());return 1;}if(FD_ISSET(remoteSocket,&fdread)){WaitForSingleObject(hRecvEvent,INFINITE);nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);            if (nRecv_len==SOCKET_ERROR) {printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());return 1;}            if(nRecv_len==0){printf("Connection Closed!\n");break;}       buffer[nRecv_len] = '\0';printf("[Normal]: %s\n", buffer);}}return 0;}int main(int argc, char *argv[]){WSADATA wsaData;int nErr;SOCKET myListener = INVALID_SOCKET;struct sockaddr_in localIp;unsigned short nPort; DWORD dwThreadId;HANDLE hThread=NULL;if (argc!=2){printf("MyServer <Port>\n");return 0;}nPort = (unsigned short)atol(argv[1]);nErr = WSAStartup(MAKEWORD(2,0),&wsaData);assert(nErr==0);assert(wsaData.wVersion == MAKEWORD(2,0));myListener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);assert(myListener!=INVALID_SOCKET);// Bind the listen socket to any local IP address.localIp.sin_family = AF_INET;localIp.sin_port = htons(nPort);;localIp.sin_addr.S_un.S_addr = INADDR_ANY;nErr = bind(myListener,(SOCKADDR *)&localIp,sizeof(localIp));assert(nErr!=SOCKET_ERROR);nErr = listen(myListener, 5);assert(nErr==0);//Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");if (hRecvEvent == NULL) { printf("CreateEvent failed with error 0x%lx\n", GetLastError());return 1;}printf("The server is ready!\n");for (;;) {struct sockaddr_in remoteIp;SOCKET remoteSocket = INVALID_SOCKET;int nAddrLen = sizeof(SOCKADDR);remoteSocket = accept(myListener, (SOCKADDR *)(&remoteIp), &nAddrLen);if(remoteSocket == INVALID_SOCKET) {int error = WSAGetLastError();printf("Accept() failed. Win32 error is 0x%lx\n", GetLastError());goto Cleanup;} else {printf("Connected from %d.%d.%d.%d:%d\n", remoteIp.sin_addr.S_un.S_un_b.s_b1,remoteIp.sin_addr.S_un.S_un_b.s_b2,remoteIp.sin_addr.S_un.S_un_b.s_b3,remoteIp.sin_addr.S_un.S_un_b.s_b4,ntohs(remoteIp.sin_port));BYTE buffer[1+1];int nRecv_len=recv(remoteSocket,(char *)&buffer,1,0);if (nRecv_len==SOCKET_ERROR) {printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());return 1;}    buffer[nRecv_len] = '\0';if(strcmp((char *)buffer,"U")==0)hThread=CreateThread(0,0,OOBHandler,(LPVOID)remoteSocket, 0, &dwThreadId);else if(strcmp((char *)buffer,"N")==0)hThread=CreateThread(0,0,NormalHandler,(LPVOID)remoteSocket, 0, &dwThreadId);           if(hThread==0){printf("CreateThread() failed: %d\n",GetLastError());return 1;}CloseHandle(hThread);}}closesocket(myListener);Cleanup:WSACleanup();return 0;}

عودة إلى الأعلى

اختبار العينة

  1. في موجه الأوامر ، اكتب ميسيرفير 4444 لبدء تشغيل الخادم علي منفذ 4444. يعرض تطبيق الخادم الرسالة التالية ثم تنتظر العملاء:

    الخادم جاهز!

  2. في نافذه موجه أوامر مختلفه ، اكتبميكلينت IPAddress 4444 لبدء تشغيل العميل. ملاحظة يتم إصدار Acrobat Reader من قِبل شركة Adobe Systems Inc.‎. العنصر النائب IPAddress هو عنصر نائب لعنوان IP الخاص بالخادم.

  3. يعرض الخادم رسالة مماثله لما يلي:

    Waiting.Waiting*..*عند تلقي الرسالة السابقة ، يجب كتابه أبكديفغي علي العميل خلال 10 ثوان قبل متابعه الخادم.

بعد مرور 10 ثوان ، يعرض الخادم ما يلي:

[الOOB]: ببببببببب [OOB]: ددددددددد [oob]: FFFFFFFFFF [OOB]: ه [Normal]: كككككككككك [Normal]: ي [normal]: ججججججججج [عادي]) الييييييييي [عادي]عودة إلى الأعلى

المراجع

للحصول علي مزيد من المعلومات ، قم بزيارة مواقع الويب التالية لمطوري Microsoft (MSDN):

البروتوكولات المستقلة عن البيانات خارج النطاقhttp://msdn2.microsoft.com/en-us/library/ms740102.aspxوظائف Winsockhttp://msdn2.microsoft.com/en-us/library/ms741394.aspxللحصول علي مزيد من المعلومات ، انقر فوق رقم المقالة التالية لعرض المقالة في قاعده معارف Microsoft:

331756 تعذر علي الدالة إيوكتلسوكيت الكشف عن البيانات المضمنة في نطاقعوده لاعلي

هل تحتاج إلى مزيد من المساعدة؟

توسيع المهارات
استكشاف التدريب
الحصول على الميزات الجديدة أولاً
الانضمام إلى Microsoft Insider

هل كانت المعلومات مفيدة؟

نشكرك على ملاحظاتك!

شكراً لك على الملاحظات! يبدو أنه من المفيد إيصالك بأحد وكلاء دعم Office لدينا.

×