C++ 黑客编程揭秘与防范(第3版)
上QQ阅读APP看书,第一时间看更新

2.2.1 基于TCP的通信

1.服务器端代码

回顾一下前面的知识,创建一个TCP的服务器端的程序需要调用的函数流程如下:

        WSAStartup()->socket()->bind()->listen()->accept()->send()/recv()->closesocket()->
    WSACleanup()

只要依次调用上面的函数就可以完成一个服务器端的程序了,是不是如同搭积木一样简单?服务器端的代码如下:

        #include <stdio.h>
        #include <winsock2.h>
        #pragma comment (lib, "ws2_32")

        int main()
        {
            WSADATA wsaData;
            WSAStartup(MAKEWORD(2, 2), &wsaData);

            // 创建套接字
            SOCKET sLisent = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

            // 对sockaddr_in结构体填充地址、端口等信息
            struct sockaddr_in ServerAddr;
            ServerAddr.sin_family = AF_INET;
            ServerAddr.sin_addr.S_un.S_addr = inet_addr("10.10.30.12");
            ServerAddr.sin_port = htons(1234);

            // 绑定套接字与地址信息
            bind(sLisent, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr));

            // 端口监听
            listen(sLisent, SOMAXCONN);

            // 获取连接请求
            sockaddr_in ClientAddr;
            int nSize = sizeof(ClientAddr);

            SOCKET sClient = accept(sLisent, (SOCKADDR *)&ClientAddr, &nSize);
            // 输出客户端使用的IP地址和端口号
            printf("ClientIP=%s:%d\r\n",inet_ntoa(ClientAddr.sin_addr),
                    ntohs(ClientAddr.sin_port));

            // 发送消息
            char szMsg[MAXBYTE] = { 0 };
            lstrcpy(szMsg, "hello Client!\r\n");
            send(sClient, szMsg, strlen(szMsg) + sizeof(char), 0);

            // 接收消息
            recv(sClient, szMsg, MAXBYTE, 0);
            printf("Client Msg : %s \r\n", szMsg);

            WSACleanup();

            return 0;
        }

这样一个服务器端的程序就完成了。为了起到演示的作用,不让多余的东西影响流程的清晰化,这里没有对API函数的返回值进行判断。在实际的开发中,为了保证程序的健壮性,应该对各函数的返回值进行判断,以免程序中产生异常。

由于代码中有详细的注释,并且前面对各Winsock函数有详细的介绍,这里就不再对代码进行解释了。

2.客户端代码

在客户端中同样也是调用前面介绍的API函数进行搭积木式的编程就可以了。客户端的代码调用API的流程如下:

        WSAStartup()->socket()->connect()->send()/recv()->closesocket()->WSACleanup()

有了调用的流程,就可以开始完成代码了。客户端的代码如下:

        #include <stdio.h>
        #include <winsock2.h>
        #pragma comment (lib, "ws2_32")
        int main()
        {
            WSADATA wsaData;
            WSAStartup(MAKEWORD(2, 2), &wsaData);

            // 创建套接字
            SOCKET sServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

            // 对sockaddr_in结构体填充地址、端口等信息
            struct sockaddr_in ServerAddr;
            ServerAddr.sin_family = AF_INET;
            ServerAddr.sin_addr.S_un.S_addr = inet_addr("10.10.30.12");
            ServerAddr.sin_port = htons(1234);

            // 连接服务器
            connect(sServer, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr));

            char szMsg[MAXBYTE] = { 0 };

            // 接收消息
            recv(sServer, szMsg, MAXBYTE, 0);
            printf("Server Msg : %s \r\n", szMsg);

            // 发送消息
            lstrcpy(szMsg, "hello Server!\r\n");
            send(sServer, szMsg, strlen(szMsg) + sizeof(char), 0);

            WSACleanup();

            return 0;
        }

以上代码就是客户端的代码,同样也非常简单。在VC6中创建控制台的应用程序,在创建项目是选择“Win32 Console Application”。这里要分别为服务器端程序和客户端程序创建项目,然后分别将服务器端代码和客户端代码进行编译连接。代码都编译连接完成以后,首先运行服务器端程序,再运行客户端程序,这样第一个基于TCP的服务器端程序和客户端程序就完成了。