C++封装的基于WinSock2的TCP服务端、客户端

无聊研究Winsock套接字编程,用原生的C语言接口写出来的代码看着难受,于是自己简单用C++封装一下,把思路过程理清,方便自己后续翻看和新手学习。

只写好了TCP通信服务端,有空把客户端流程也封装一下。

先上主函数:

// main.cpp : 异想家sandeepin poi!  

#include "stdafx.h"  

#include <iostream>  

extern int JTCPserver();  

extern int JTCPclient();  

int main()  

{  

    JTCPserver(); // 两者选一  

//  JTCPclient();  

    return 0;  

}  

JTCPserver.cpp内容:

// JTCPserver.cpp : 蒋方正封装的TCP服务端  

  

#include "stdafx.h"  

#include <iostream>  

#include <string>  

#include <WinSock2.h> // WinSocket   

#include <WS2tcpip.h> // IP地址转换用到inet_pton  

#pragma comment(lib,"ws2_32.lib")    

using namespace std;  

  

// 【1】初始化WinSock  

bool initWinSock();  

// 【2】创建socket  

bool createSocket(SOCKET &listenScok);  

// 【3】socket绑定本机地址信息  

bool bindIPandPort(SOCKET &listenScok, const string ip, const unsigned short port);  

// 【4】侦听socket,接收客户端请求  

bool listenSocket(SOCKET &listenScok);  

// 【5】等待客户端连接-阻塞  

bool waitClientConnect(SOCKET &listenScok, SOCKET &clientSock);  

// 【6】接收数据-阻塞  

bool receiveData(SOCKET &clientSock, string &data);  

// 【7】停止套接字的接收、发送  

bool shutdownSocket(SOCKET &clientSock);  

// 【8】发送信息  

bool sendData(SOCKET &clientSock, const string &data);  

  

int JTCPserver()  

{         

    SOCKET listenScok;  // 服务端Socket  

    SOCKET clientSock;  // 客户端Socket  

    string data;        // 收到的数据  

  

    // 【1】初始化WinSock  

    initWinSock();  

    // 【2】创建socket  

    createSocket(listenScok);  

    // 【3】socket绑定本机地址信息  

    bindIPandPort(listenScok, "127.0.0.1", 1994);  

    // 【4】侦听socket,接收客户端请求  

    listenSocket(listenScok);  

  

    // 坐等客户端连接  

    bool isClientSockConnect = false;   // 是否有客户端连进来  

    bool isReceiveData = false;         // 是否接收数据成功  

  

    while (true)  

    {   

        if (!isClientSockConnect)  

        {  

            // 【5】等待客户端连接  

            isClientSockConnect = waitClientConnect(listenScok, clientSock);  

        }  

        else  

        {  

            if(!isReceiveData)  

            {  

                // 【6】接收数据-阻塞  

                isReceiveData = receiveData(clientSock, data);  

                // 如果接收数据失败则断开  

                if(!isReceiveData)   

                {  

                    // 【7】停止套接字的接收、发送  

                    shutdownSocket(clientSock);  

                    cout << "等待客户端再连接..." << endl;  

                    isClientSockConnect = false; // 可以重连了  

                }  

            }  

            if(isReceiveData && data != "jfzpoi"  && data != "@end#")  

            {  

                isReceiveData = false;  

            }  

            if(isReceiveData && data == "jfzpoi")  

            {  

                // 【8】发送信息(收的数据为jfzpoi)  

                sendData(clientSock, "sandeepin!\r\n");  

                isReceiveData = false;  

            }  

            if (isReceiveData && data == "@end#")  

            {  

                // 【9】关闭相关  

                int err;  

//              err = shutdown(listenScok, 2);  

//              if (err == SOCKET_ERROR)  

//              {  

//                  cout << "关闭失败!" << endl;  

//              }  

                // 关闭套接字,释放资源  

                err = closesocket(listenScok);  

                if (err == SOCKET_ERROR)  

                {  

                    cout << "关闭socket失败!" << endl;  

                }  

                // 停止使用WinSock库,释放对应资源  

                if (WSACleanup() != 0)  

                {  

                    cout << "WSA清空失败!" << endl;  

                }  

                cout << "关完了,坐等关机!poi" << endl;  

                return 0;  

            }  

        }  

    }  

}  

  

// 【1】初始化WinSock  

bool initWinSock()  

{  

    WORD verision = MAKEWORD(2, 2);  

    WSADATA lpData;  

    int intEr = WSAStartup(verision, &lpData); // 指定winsock版本并初始化  

    if (intEr != 0)  

    {  

        cout << "WinSock初始化失败!" << endl;  

        return false;  

    }  

    cout << "WinSock初始化成功!" << endl;  

    return true;  

}  

  

// 【2】创建socket  

bool createSocket(SOCKET &listenScok)  

{  

    // 创建侦听socket    

    listenScok = socket(AF_INET, SOCK_STREAM, 0);  

    if (listenScok == INVALID_SOCKET)  

    {  

        cout << "socket创建失败!" << endl;  

        return false;  

    }  

    cout << "socket创建成功!" << endl;  

    return true;  

}  

  

// 【3】socket绑定本机地址信息  

bool bindIPandPort(SOCKET &listenScok, const string ip, const unsigned short port)  

{  

    // 制作sockaddr_in结构体  

    // 在bind函数,connect函数里提到了套接字编程网络地址信息结构体const struct sockaddr和const struct sockaddr_i  

    sockaddr_in hostAddr;  

    hostAddr.sin_family = AF_INET;  

    hostAddr.sin_port = htons(port);//转换成网络字节序    

                                    //hostAddr.sin_addr.S_un.S_addr = inet_addr(SERVERIP);//转换成网络字节序    

                                    //cout << "net IP:" << hostAddr.sin_addr.S_un.S_addr << endl;    

                                    /* 

                                    inet_addr()版本太低,被弃用使用inet_pton(协议族,字符串IP地址,void目标in_addr*) 

                                    头文件:WS2tcpip.h 

                                    */  

    in_addr addr;  

    inet_pton(AF_INET, ip.c_str(), (void*)&addr);  

    hostAddr.sin_addr = addr;  

    cout << "ip(网络字节序):" << addr.S_un.S_addr << endl;  

    cout << "ip(常规形式):" << ip.c_str() << endl;  

  

    // 侦听套接字listenSock绑定本机地址信息    

    int err = bind(listenScok, (struct sockaddr*)&hostAddr, sizeof(sockaddr));  

    if (err != 0)  

    {  

        cout << "本地IP绑定失败!" << endl;  

        return false;  

    }  

    return true;  

}  

  

// 【4】侦听socket,接收客户端请求  

bool listenSocket(SOCKET &listenScok)  

{  

    // 设定套接字为侦听状态,准备接收客户机进程发送来的连接请求  

    int err = listen(listenScok, 3);  

    if (err != 0)  

    {  

        cout << "socket监听失败!" << endl;  

        return false;  

    }  

    cout << "监听客户端连接中……" << endl;  

    return true;  

}  

  

// 【5】等待客户端连接-阻塞  

bool waitClientConnect(SOCKET &listenScok, SOCKET &clientSock)  

{  

    sockaddr_in clientAddr;  

    int len = sizeof(struct sockaddr); // 必须指定长度,否则会导致accept返回10014错误  

                                       // accept会循环等待客户端连接  

    clientSock = accept(listenScok, (struct sockaddr*)&clientAddr, &len);  

    cout << "客户端Socket编号:" << clientSock << endl;  

    if (clientSock == INVALID_SOCKET)  

    {  

        cout << "客户端连接失败!" << endl;  

        cout << WSAGetLastError() << endl;  

        return false;  

    }  

    return true;  

}  

  

// 【6】接收数据-阻塞  

bool receiveData(SOCKET &clientSock, string &data)  

{  

    static int cnt = 1; // 接收数据编号-静态  

                        // 通过已建立连接的套接字,接收数据 设定缓冲1024字节  

    char buf[1024] = "\0";  

    // flags操作方式(0正常数据,MSG_PEED系统缓冲区的数据复制到所提供的接收缓冲区内,系统缓冲区数据未删除,MSG_OOB处理带外数据,通常用参数0即可)  

    int buflen = recv(clientSock, buf, 1024, 0);  

    if (buflen == SOCKET_ERROR)  

    {  

        cout << "接收失败!" << endl;  

        return false;  

    }  

    // 一切正常则显示接收数据  

    data = string(buf);  

    cout << "收到第" << cnt++ << "次,内容为:\n" << buf << endl;  

    return true;  

}  

  

// 【7】停止套接字的接收、发送  

bool shutdownSocket(SOCKET &clientSock)  

{  

    //(收完就关)停止套接字的接收、发送功能(0禁止接收,1禁止发送,2禁制接收发送)  

    int err = shutdown(clientSock, 2);  

    if (err == SOCKET_ERROR)  

    {  

        cout << "关闭Socket失败!" << endl;  

        return false;  

    }  

    return true;  

}  

  

// 【8】发送信息  

bool sendData(SOCKET &clientSock, const string &data)  

{  

  

    int err = send(clientSock, data.c_str(), data.size(), 0);  

    if (err == SOCKET_ERROR)  

    {  

        cout << "发送失败!" << endl;  

        return false;  

    }  

    cout << "发送数据为:\n" << data << endl;  

    return true;  

}  

JTCPclient.cpp内容:

// JTCPclient.cpp : 蒋方正封装的TCP客户端代码  

  

#include "stdafx.h"    

#include <iostream>  

#include <WinSock2.h>    

#include <WS2tcpip.h>    

#pragma comment(lib,"ws2_32.lib")  

using namespace std;  

  

// 【1】初始化WinSock  

bool initWinSockC();  

// 【2】创建socket  

bool createSocketC(SOCKET &listenScok);  

// 【3】连接到服务器  

bool connectSocketC(SOCKET &conSock, const string ip, const unsigned short port);  

// 【4】发送数据  

bool sendDataC(SOCKET &clientSock, const string &data);  

// 【5】接收数据  

bool receiveDataC(SOCKET &clientSock, string &data);  

  

int JTCPclient()  

{  

    SOCKET clientSock;  // 客户端Socket  

    string data;        // 收到的数据  

  

    bool isCreateSocket = false;    // 是否创建了Socket  

    bool isConnectSocket = false;   // 是否连上了服务器  

    bool isSendDataOK = false;      // 是否发送成功数据  

    bool isReceiveDataOK = false;   // 是否接收成功数据  

  

    // 【1】初始化WinSock  

    if(initWinSockC())  

    {  

        while (true)  

        {  

            if(!isCreateSocket)  

            {  

                // 【2】创建socket  

                createSocketC(clientSock);  

                isCreateSocket = true;  

            }  

            else  

            {  

                if(!isConnectSocket)  

                {  

                    // 【3】连接到服务器  

                    connectSocketC(clientSock, "127.0.0.1", 1994);  

                    isConnectSocket = true;  

                }  

                else  

                {  

                    if(!isSendDataOK)  

                    {  

                        // 【4】发送数据  

                        isSendDataOK = sendDataC(clientSock, "jfz hello\r\n");  

                    }  

                    else  

                    {  

                        if(!isReceiveDataOK)  

                        {  

                            // 【5】接收数据  

                            isReceiveDataOK = receiveDataC(clientSock, data);  

                        }  

                        else  

                        {  

                            if(data == "@end#")  

                            {  

                                WSACleanup();  

                                return 0;  

                            }  

                            isReceiveDataOK = false;  

                            isSendDataOK = false;  

                        }  

                    }  

                      

                }  

            }  

        }  

    }  

    return 0;  

}  

  

// 【1】初始化WinSock  

bool initWinSockC()  

{  

    WORD verision = MAKEWORD(2, 2);  

    WSADATA lpData;  

    int intEr = WSAStartup(verision, &lpData); // 指定winsock版本并初始化  

    if (intEr != 0)  

    {  

        std::cout << "WinSock初始化失败!" << endl;  

        return false;  

    }  

    std::cout << "WinSock初始化成功!" << endl;  

    return true;  

}  

  

// 【2】创建socket  

bool createSocketC(SOCKET &listenScok)  

{  

    // 创建侦听socket    

    listenScok = socket(AF_INET, SOCK_STREAM, 0);  

    if (listenScok == INVALID_SOCKET)  

    {  

        cout << "socket创建失败!" << endl;  

        return false;  

    }  

    cout << "socket创建成功!" << endl;  

    return true;  

}  

  

// 【3】连接到服务器  

bool connectSocketC(SOCKET &conSock, const string ip, const unsigned short port)  

{  

    // 建立地址结构体  

    sockaddr_in hostAddr;  

    hostAddr.sin_family = AF_INET;  

    hostAddr.sin_port = htons(port);//转换成网络字节序    

                                    //hostAddr.sin_addr.S_un.S_addr = inet_addr(SERVERIP);//转换成网络字节序    

                                    //cout << "net IP:" << hostAddr.sin_addr.S_un.S_addr << endl;    

                                    /* 

                                    inet_addr()版本太低,被弃用使用inet_pton(协议族,字符串IP地址,void目标in_addr*) 

                                    头文件:WS2tcpip.h 

                                    */  

    in_addr addr;  

    inet_pton(AF_INET, ip.c_str(), (void*)&addr);  

    hostAddr.sin_addr = addr;  

    cout << "ip(网络字节序):" << addr.S_un.S_addr << endl;  

    cout << "ip(常规形式):" << ip.c_str() << endl;  

  

    // 向服务器提出连接请求  

    int err = connect(conSock, (sockaddr*)&hostAddr, sizeof(sockaddr));  

    if (err == INVALID_SOCKET)  

    {  

        cout << "连接服务器失败!" << endl;  

        return false;  

    }  

    return true;  

}  

  

// 【4】发送数据  

bool sendDataC(SOCKET &clientSock, const string &data)  

{  

    int err = send(clientSock, data.c_str(), data.size(), 0);  

    if (err == SOCKET_ERROR)  

    {  

        cout << "发送失败!" << endl;  

        return false;  

    }  

    cout << "发送数据为:\n" << data.c_str() << endl;  

    return true;  

}  

  

// 【5】接收数据  

bool receiveDataC(SOCKET &clientSock, string &data)  

{  

    static int cnt = 1; // 接收数据编号-静态  

                        // 通过已建立连接的套接字,接收数据 设定缓冲1024字节  

    char buf[1024] = "\0";  

    // flags操作方式(0正常数据,MSG_PEED系统缓冲区的数据复制到所提供的接收缓冲区内,系统缓冲区数据未删除,MSG_OOB处理带外数据,通常用参数0即可)  

    int buflen = recv(clientSock, buf, 1024, 0);  

    if (buflen == SOCKET_ERROR)  

    {  

        cout << "接收失败!" << endl;  

        return false;  

    }  

    // 一切正常则显示接收数据  

    data = string(buf);  

    cout << "收到第" << cnt++ << "次,内容为:\n" << buf << endl;  

    return true;  

}