Bỏ qua để tới nội dung chính
Đăng nhập với Microsoft
Đăng nhập hoặc tạo một tài khoản.
Xin chào,
Chọn một tài khoản khác.
Bạn có nhiều tài khoản
Chọn tài khoản bạn muốn đăng nhập.

Tóm tắt

Đôi khi bạn phải gửi dữ liệu ra ngoài của ban nhạc khẩn cấp (OOB) vào bộ thu của bạn. Bộ thu là bất kỳ người dùng nào hoặc bất kỳ ứng dụng nào nhận được dữ liệu. Bạn muốn dữ liệu OOB được xử lý như dữ liệu ưu tiên cao hơn bất kỳ dữ liệu thông thường nào mà bạn có thể gửi. Nếu dữ liệu OOB mà bạn muốn gửi là một byte, bạn có thể sử dụng hàm Select để tìm kiếm dữ liệu OOB. Bạn có thể sử dụng hàm recv để đọc dữ liệu. Tuy nhiên, trong giao thức điều khiển truyền dẫn (TCP), khối dữ liệu OOB luôn là một byte. Do đó, nếu bạn gửi dữ liệu OOB nhiều byte, chỉ có byte cuối cùng của dữ liệu OOB được truy xuất. Dữ liệu còn lại được xử lý như dữ liệu bình thường. Bài viết này sử dụng mã mẫu để mô tả cách gửi dữ liệu nhiều byte OOB bằng cách dùng ổ cắm Microsoft Windows (Winsock).

TRONG TÁC VỤ NÀY

GIỚI THIỆU

Bài viết này mô tả cách gửi dữ liệu ngoài-byte (chars) trong ban đầu bằng cách dùng Winsock. Các ứng dụng mẫu được tạo trong Microsoft Visual C++. Vì cơ chế OOB này không được hỗ trợ trực tiếp ở mức Microsoft Windows socket, bạn phải thực hiện cơ chế OOB này ở mức ứng dụng. Điều này không đúng dữ liệu OOB. Trong ứng dụng mẫu này, bạn tạo hai ổ cắm ở phía máy khách, còn được gọi là bên người gửi, để gửi dữ liệu OOB và dữ liệu thông thường. Ở phía máy chủ, còn được gọi là bên nhận, bạn sử dụng hai ổ cắm để xử lý dữ liệu trong hai chủ đề. Một chuỗi cho dữ liệu OOB. Các chuỗi khác là dành cho dữ liệu bình thường. Để mô phỏng cơ chế OOB, bạn phải đồng bộ hai chủ đề này. Hãy đảm bảo rằng chuỗi xử lý dữ liệu OOB có mức ưu tiên cao hơn so với chuỗi quy trình dữ liệu chuẩn.Lưu ý Ứng dụng mẫu này mô tả một cách để gửi dữ liệu nhiều byte OOB. Bạn có thể phải sửa đổi mã để làm cho mã đó hoạt động trong môi trường của bạn.quay lại đầu trang

Tạo một ứng dụng khách

  1. Tạo một ứng dụng khách. Trong ứng dụng máy khách này, mã mẫu sau đây mô tả cách tạo hai ổ cắm:

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

    Biến số Myoobsocket được dùng để gửi dữ liệu OOB. Biến đổi Mynormalsocket được dùng để gửi dữ liệu chuẩn.

  2. Vì dữ liệu mà biến số sẽ không đúng với dữ liệu OOB, bạn phải có cách để thông báo cho máy chủ loại dữ liệu mà socket có nghĩa vụ phải gửi trước khi bạn bắt đầu gửi dữ liệu. Mã mẫu sau đây mô tả cách gửi một ký tự ban đầu để thông báo cho máy chủ về loại dữ liệu nào sẽ được gửi đi. Sử dụng "U" cho dữ liệu OOB và sử dụng "N" cho dữ liệu chuẩ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. Mã mẫu sau đây mô tả cách đặt ứng dụng máy khách theo dõi đầu vào từ người dùng. Ứng dụng máy khách sẽ gửi các ký tự viết hoa dưới dạng dữ liệu OOB. Nhân đôi mỗi ký tự nhập vào để soạn một chuỗi nhiều byte.

    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);}...}

Hiển thị mã mẫu cho ứng dụng khách, Myclient. cpp trở về đầu trang

Tạo một ứng dụng máy chủ

  1. Ở phía máy chủ, mã mẫu sau đây mô tả cách tạo ổ cắm nghe để giám sát cổng được dùng để liên lạc:

    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. Mã mẫu sau đây mô tả cách gọi hàm Accept để làm cho socket Listener chờ cho kết nối đến sẽ cố gắng:

    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. Để mô phỏng cơ chế OOB, bạn phải đồng bộ hai chủ đề này. Trong ứng dụng mẫu này, hãy dùng đối tượng sự kiện toàn cầu để thực hiện điều này. Đặt câu lệnh sau đây ở phía trên cùng của tệp.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Tạo bộ xử lý OOB được thực thi bởi một chuỗi riêng biệt. Trong bộ xử lý này, bạn sử dụng hàm Select để phát hiện khi dữ liệu đến. Khi dữ liệu đến, hãy làm theo các bước sau đây:

    1. Gọi hàm Resetevent để đặt đối tượng sự kiện hrecvevent vào trạng thái không đăng ký.

      ResetEvent(hRecvEvent);

      Điều này chặn việc xử lý dữ liệu thông thường được thực thi trong một chuỗi khác.

    2. Gọi hàm revc để đọc dữ liệu.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Vì dữ liệu khác có thể được gửi so với bộ đệm có thể giữ, hãy gọi lại vào hàm recv , cùng với cờ MSG_PEEK , để xác định xem mọi dữ liệu có sẵn trên dây không.

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

      Sử dụng một trong các phương pháp sau đây, tùy thuộc vào việc bạn đang chờ xử lý dữ liệu hay không:

      • Nếu không có dữ liệu nào đang chờ xử lý, hãy gọi hàm Setevent để đặt đối tượng sự kiện đã xác định cho trạng thái signaled.

        SetEvent(hRecvEvent);

        Khi bạn thực hiện điều này, Chuỗi xử lý dữ liệu chuẩn hóa có thể tiếp tục. Chuỗi xử lý dữ liệu thông thường chờ cho đối tượng sự kiện Hrecvevent trước chuỗi trình xử lý dữ liệu chuẩn hóa.

      • Nếu dữ liệu vẫn đang chờ xử lý để đọc, hãy gọi hàm recv một lần nữa để đọc dữ liệu còn lại. Sau đó, hãy xem lại dữ liệu đang chờ xử lý.

    Lặp lại các bước 4A đến 4c cho đến khi tất cả dữ liệu đang chờ xử lý đã được đọc.

  5. Tạo bộ xử lý dữ liệu chuẩn hóa. Bộ điều khiển này tương tự như trình xử lý dữ liệu OOB, ngoại trừ việc xử lý dữ liệu bình thường gọi hàm Waitforsingleđối tượng khi trình xử lý dữ liệu thông thường phát hiện rằng dữ liệu đã đến.

    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.

Hiển thị mã mẫu cho ứng dụng máy chủ, myserver. cpp trở về đầu trang

Hiển thị mã mẫu cho ứng dụng khách, Myclient. cpp

Lưu ý Bạn phải bao gồm một tham chiếu đến tệp thư viện Winsock, Ws2_32. lib, để tạo mã bản dịch.

#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;}

quay lại đầu trang

Hiển thị mã mẫu cho ứng dụng máy chủ, myserver. cpp

Lưu ý Bạn phải bao gồm một tham chiếu đến tệp thư viện Winsock, Ws2_32. lib, để tạo mã bản dịch.

#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;}

quay lại đầu trang

Kiểm tra mẫu

  1. Tại dấu nhắc lệnh, nhập myserver. exe 4444 để bắt đầu máy chủ trên cổng 4444. ứng dụng máy chủ Hiển thị thông báo sau đây và sau đó đợi cho khách hàng:

    Máy chủ đã sẵn sàng!

  2. Trong cửa sổ nhắc lệnh khác, nhậpMyclient ipaddress 4444 để bắt đầu máy khách. Lưu ý Địa chỉ ipholder là chỗ dành sẵn cho địa chỉ IP của máy chủ.

  3. Máy chủ Hiển thị thông báo tương tự như sau:

    Waiting.Waiting*..*Khi bạn nhận được thư trước đó, bạn phải nhập Abcdefghi trên máy khách trong vòng 10 giây trước khi máy chủ tiếp tục.

Sau khoảng 10 giây, máy chủ sẽ hiển thị như sau:

[OOB]: BBBBBBBBBB [OOB]: DDDDDDDDDD [OOB]: FFFFFFFFFF [OOB]: HHHHHHHHHH [Normal]: MC [bình thường]: tggeeeeee [Normal]: gggggggggg [Normal]: iiiiiiiiii, không có trong đóquay lại đầu trang

Tham khảo

Để biết thêm thông tin, hãy truy cập trang web mạng Microsoft Developer Network (MSDN) sau đây:

Giao thức-các hàmhttp://msdn2.Microsoft.com/en-US/Library/ms740102.aspxWinsock dữ liệu vắng mặt độc lậphttp://msdn2.Microsoft.com/en-US/Library/ms741394.aspxĐể biết thêm thông tin, hãy bấm số bài viết sau đây để xem bài viết trong cơ sở kiến thức Microsoft:

331756 Hàm Ioctlsocket không thể phát hiện dữ liệu trong dải băng vắng mặttrở về đầu trang

Bạn cần thêm trợ giúp?

Bạn muốn xem các tùy chọn khác?

Khám phá các lợi ích của gói đăng ký, xem qua các khóa đào tạo, tìm hiểu cách bảo mật thiết bị của bạn và hơn thế nữa.

Cộng đồng giúp bạn đặt và trả lời các câu hỏi, cung cấp phản hồi và lắng nghe ý kiến từ các chuyên gia có kiến thức phong phú.

Thông tin này có hữu ích không?

Bạn hài lòng đến đâu với chất lượng dịch thuật?
Điều gì ảnh hưởng đến trải nghiệm của bạn?
Khi nhấn gửi, phản hồi của bạn sẽ được sử dụng để cải thiện các sản phẩm và dịch vụ của Microsoft. Người quản trị CNTT của bạn sẽ có thể thu thập dữ liệu này. Điều khoản về quyền riêng tư.

Cảm ơn phản hồi của bạn!

×