增强你的 PocketPC 应用程序的 TCP/IP 能力
建立与其他应用程序的 TCP/IP 连接。
引言
每个人都应该了解如何在 eMbedded Visual Basic 3.0 中访问 Winsock。 就像我在 Visual Basic 中做的那样,它非常容易和直接。 但是 eMbedded Visual C++ 3.0 怎么样呢?
用于 MS Windows CE 的 Winsock 不支持 WSAAsyncSelect
。 因此,我们需要编写大量的代码以及同步线程来处理我们自己的传入和传出数据。
使用代码
发布的代码是整个示例项目。 因此,您可能需要剪切并粘贴以下函数,以便在您自己的项目中使用这段代码。 不用担心,代码很容易识别,您只需要过滤掉我所有的演示项目 GUI 界面控制代码。
以下是您需要复制的三个基本函数和两个同步线程
// Function int InitSocket (HWND); // Initialize the Winsock.DLL void OpenSocket (HWND); // Open the server side socket void CloseSocket(HWND); // Close the server side socket // Synchronization Thread // Waiting for the incoming connection request DWORD WINAPI StartListen (LPVOID pParam); // Reading the incoming buffer DWORD WINAPI ReadInBuffer (LPVOID pParam);
复制代码后,您需要按顺序调用上述三个函数。 因为它们中的每一个都执行一个特定的任务。 嗯... 让我们看一下下面的第一个函数 InitSocket
。 基本上,它所做的只是在我们可以继续创建/使用任何套接字之前,通过调用 WSAStartup
API 来初始化 Winsock 组件(版本 1.1)。
WSADATA wsaData; // Initliatize the Winsock dll version 1.1 if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) { // Fail to initialize the winsock dll MessageBox(hWnd, TEXT("Fail to initialize the Winsock DLL!"), TEXT("MySocket"), MB_OK | MB_ICONEXCLAMATION); // Set the return value return 1; } else // Successful initialize the Winsock DLL // Set the return value return 0;
其次,我们需要创建一个新的套接字来监听特定端口号上的传入请求(连接到主机)并接受连接请求(建立连接)。 但是您会注意到 OpenSocket
下面有一些额外的代码,这些代码用于处理 GUI 控件,以确定要创建的套接字是处于服务器模式还是客户端模式。 这是因为两者将具有两种不同的逻辑流程和特征。
因此,如果要创建的套接字处于服务器模式,您需要做的是继续创建同步线程 (StartListen
)。 否则,您将需要执行以下代码来建立与特定主机的连接,然后创建 ReadInBuffer
同步线程。
注意:所有非相关的 GUI 代码都在以下显示的代码中过滤掉了(但不在附加的演示项目代码中)。 您可能需要将您自己的 GUI 控制/更新的代码添加到此函数中。
// Reset the SOCKADDR_IN struct memset(&sckAddress, 0, sizeof(sockaddr_in)); // Setup the sckClient socket sckClient = socket(AF_INET, SOCK_STREAM, 0); sckAddress.sin_port = htons(atoi(port)); sckAddress.sin_family = AF_INET; sckAddress.sin_addr.s_addr = inet_addr(host); if(connect(sckClient, (struct sockaddr *)&sckAddress, sizeof(sckAddress)) != SOCKET_ERROR) // Create read input buffer thread hThread2 = CreateThread(NULL, 0, ReadInBuffer, hWnd, 0, &dwThreadID); else // Notify user about the error MessageBox(hWnd, TEXT("Client~Fail to establish the connection!"), TEXT("MySocket"), MB_OK | MB_ICONEXCLAMATION);
StartListen
同步线程里面是什么? 当您查看代码时,您会发现它是一个无限的 do...while
循环,并在该线程中对每个循环中的套接字状态进行检查,直到获得有效的套接字句柄,如下面的代码所示
if(sckServer != INVALID_SOCKET) { // Setup the port number, protocol & etc.. sckAddress.sin_port = htons(atoi(port)); sckAddress.sin_family= AF_INET; sckAddress.sin_addr.s_addr = INADDR_ANY; // Bind the socket bind(sckServer, (struct sockaddr *)&sckAddress, sizeof(sckAddress)); // Listen to the specific port for 1 client connection only listen(sckServer, 1); // Start looping and check the respective port for incoming request do { // Socket callback status structure fds; // Maximum wait time for the "select" command tv.tv_sec = 1; tv.tv_usec = 1; // Initialize the fd_set structure to NULL FD_ZERO (&fds); // Add the sckServer socket to fd_set structure FD_SET (sckServer, &fds); // Call the select command if (select(0, &fds, NULL, NULL, &tv) == 0) // Maximum wait time is expired. continue; // Check is there any incoming request/active in the fd_set structure // Zero mean no, else if (FD_ISSET(sckServer, &fds) != 0) { // Accept the incoming request sckClient = accept(sckServer, NULL, 0); // Close the existing listen socket (sckServer) closesocket(sckServer); // Reset the sckSocket variable to NULL sckServer = INVALID_SOCKET; // Update status control SetDlgItemText(hWnd, IDC_STATUS1, TEXT("Connected")); // Create read input buffer thread hThread2 = CreateThread(NULL, 0, ReadInBuffer, hWnd, 0, &dwThreadID); // Self terminate this thread break; } }while (sckServer != INVALID_SOCKET); } else // Notify user about the error MessageBox(hWnd, TEXT("Server~Fail to open the socket!"), TEXT("MySocket"), MB_OK | MB_ICONEXCLAMATION);
在这个阶段,您仍然无法从主机(客户端)连接接收任何数据。 因此,ReadInBuffer
同步线程是整个演示应用程序的核心,它使您能够从主机(客户端)连接接收任何数据。
因此,让我们看一下 ReadInBuffer
编码,并更多地了解其操作。
HWND hWnd = NULL; char *Buff=NULL; TCHAR *wBuff=NULL; int err; // map the pass in variable hWnd = (HWND)pParam; // Create new string buffer wBuff = new TCHAR[1024]; Buff = new char[1024]; if (sckClient != INVALID_SOCKET ) { // Loop until no data in the input buffer while (true) { // Reset the allocated string buffer memset(wBuff, TEXT('\0'), 1024*sizeof(TCHAR)); memset(Buff, '\0', 1024); // Read the data from valid socket err = recv(sckClient, Buff, 1024, 0); if (err == SOCKET_ERROR || err <= 0) { // Remote terminal reset the socket connection CloseSocket(hWnd); // Self terminate the thread break; } else { // Convert from MultiByte to UNICODE mbstowcs(wBuff, Buff, 1024); // Display the received data SetDlgItemText(hWnd, IDC_EDIT3, wBuff); } } } // Release the used memory delete Buff; // Self terminate the thread ExitThread(WM_QUIT); // Set the return value return 0;
从上面的代码中,有一个无限的 while
循环,它将不断检查套接字状态,并且当检测到无效套接字时,它将中断循环。
最后,我们必须在不使用套接字时或在检测到主机(客户端)连接丢失时销毁套接字。 因此,CloseSocket
函数非常简单,如下所示。
// Validate if(sckServer != INVALID_SOCKET) { // Close the current server side socket if (closesocket(sckServer) == 0) // Reset the sckServer sckServer = INVALID_SOCKET; else // Notify user about the error MessageBox(hWnd, TEXT("Server~Fail to close the socket."), TEXT("MySocket"), MB_OK | MB_ICONEXCLAMATION); }
PS 如果您需要获取本地机器 IP 地址,您需要做的就是调用演示应用程序中包含的 GetLocalIP
函数。
好的,明白了。