65.9K
CodeProject 正在变化。 阅读更多。
Home

增强你的 PocketPC 应用程序的 TCP/IP 能力

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (17投票s)

2002年12月20日

CPOL

3分钟阅读

viewsIcon

189534

downloadIcon

343

建立与其他应用程序的 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 函数。

好的,明白了。

© . All rights reserved.