C++ 代码实现socket 类使用TCP/IP进行通信 (windows 系统)

C++ 代码实现socket 类使用TCP/IP进行通信 (windows 系统)

TCP客户端通信常规步骤:

1.初始换socket环境
2.socket()创建TCP套接字。
3.connect()建立到达服务器的连接。
4.与客户端进行通信,recv()/send()接受/发送信息,write()/read() 子进程写入、读取信息
5. close() 关闭客户连接。

具体代码实现如下:

cpp 复制代码
/****************************************************
 *
 *@Copyright (c) 2024, GhY, All rights reserved.
 *@文件    MySocket.h
 *@描述    TCP Socket 类封装声明
 *
 *@作者    GhY
 *@日期    2024年7月24日
 *@版本    v1.0.0
 *
 ****************************************************/
#ifndef __MYSOCKET_H__
#define __MYSOCKET_H__
#include "PublicDefine.h"
#include "sigslot.h"
#include "CIniConfig.h"

/*
 *@描述:    Socket 类
 *@作者:    GhY
 *@日期:    2024/07/24
 *@历史:
 */
class MySocket : public sigslot::has_slots<>
{
public:
    typedef sigslot::signal1< Tcp_SendData* > SelectEvent;
    SelectEvent OnSelectEvent;  // 消息事件
public:
    MySocket(std::string ip = LOCAL_HOST, int port = PORT, u_long uctl = 1);
    ~MySocket();

    /*
     *@desc       初始化服务端Ip,Port配置
     *@param:     ip  port
     *@return
     *@author     GhY
     *@date       2024/07/24
     *@version    v1.0.0
     *@history:
     */
    void InitData(const std::string& ip, const int& port);

    /*
     *@brief    与服务器进行连接
     *@author   GhY
     *@date     2024/07/24
     */
    void ClientConnect();

    /*
     *@brief    关闭socket
     *@author   GhY
     *@date     2024/07/24
     */
    void Close();
    
    /*
     *@desc       发送数据
     *@param:     sdata 待发送数据
     *@return
     *@author     GhY
     *@date       2024/07/24
     *@version    v1.0.0
     *@history:
     */
    int SendData(const std::string& sdata);

    /*
     *@brief    接收数据
     *@author   GhY
     *@date     2024/07/24
     */
    int ReceiveData();

private:
    /*
     *@brief    初始化WINSOCK
     *@author   GhY
     *@date     2024/07/24
     */
    void InitWinsock();

private:
    std::string m_ip;
    int m_port;
    u_long m_uctl;  // 阻塞方式:1=非阻塞,0=阻塞 默认1

    SOCKET m_socket;
};

#endif //!__MYSOCKET_H__
cpp 复制代码
/****************************************************
*
*@Copyright (c) 2024, GhY, All rights reserved.
*@文件    MySocket.h
*@描述    TCP Socket 类封装实现
*
*@作者    GhY
*@日期    2024年7月24日
*@版本    v1.0.0
*
****************************************************/
#include "MySocket.h"
#include"winerror.h"
#pragma comment(lib, "ws2_32")
#include <time.h>
#include "CIniConfig.h"


using namespace std;


MySocket::MySocket(std::string ip, int port, u_long uctl)
    : m_ip(ip)
    , m_port(port)
    , m_uctl(uctl)
    , m_socket(NULL)
    , m_socketClient(NULL)
{
}

MySocket::~MySocket()
{
    Close();
}

void MySocket::InitData(const std::string& ip, const int& port)
{
    if (ip.empty()) {
        m_ip = LOCAL_HOST;
    } else {
        m_ip = ip;
    }
    m_port = port;
    InitWinsock();
}

void MySocket::InitWinsock()
{
    // 初始化WINSOCK
    WORD wVersionRequested = MAKEWORD(2, 2);
    WSADATA wsd;
    if (WSAStartup(wVersionRequested, &wsd) != 0) {
        std::cout << ("init WSAStartup faild") << std::endl;
    }

    if (LOBYTE(wsd.wVersion) != 2 ||
            HIBYTE(wsd.wVersion) != 2) {
        WSACleanup();
        std::cout << "WSACleanup" << std::endl;
        return;
    }
}

/************************************************************************/
/*                              客户端                                  */
/************************************************************************/

void MySocket::ClientConnect()
{
    if (m_port == 0) {
        m_port = PORT;
    }
    if (m_ip.empty()) {
        m_ip = LOCAL_HOST; //本地回路地址127,用于一台机器上测试的IP
    }
    m_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (SOCKET_ERROR == m_socket) {
        std::cout << (" create socket failed !!!") << std::endl;
        return;
    }

    int ret = ioctlsocket(m_socket, FIONBIO, &m_uctl);     //阻塞方式   FIONBIO 允许或者禁止套接字m_socket非阻塞模式  0=阻塞
    if (SOCKET_ERROR == ret) {
        std::cout << (" set ioctlsocket faild: model") << m_uctl << std::endl;
        return ;
    }
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr(m_ip.c_str());//地址,
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(m_port);//和服务器端的端口号保持一致
    connect(m_socket, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));//连接服务器端(套接字,地址转换,长度)
}



void MySocket::Close()
{
    if (m_socket != NULL) {
        closesocket(m_socket);  //关闭套接字,释放为这个套接字分配的资源
        m_socket = NULL;
    }
    WSACleanup();//终止对这个套接字库的使用
}

int MySocket::SendData(const std::string& sdata)
{
    char sendBuf[SEND_DATA_LEN];
    memset(sendBuf, 0, sizeof(sendBuf));

    std::string strId = g_ConfigPtr.getConfigValueWithKey("base", "id").c_str();
    std::string strName = g_ConfigPtr.getConfigValueWithKey("base", "name").c_str();
    int ihead = sizeof(TcpHead);
    int ibody = sizeof(TcpBody);
    Tcp_SendData* pData = (Tcp_SendData*)sendBuf;
    pData->_head._node = strId.empty() ? 0 : atoi(strId.c_str());
    pData->_head._type = 0;
    pData->_head._time = time(NULL);
    TcpBody tBody;
    tBody._length = sdata.length();
    memcpy(tBody._data, sdata.c_str(), sdata.length() + 1);
    memcpy(tBody._srcName, strName.c_str(), strName.length() + 1);
    memcpy(&sendBuf[ihead], &tBody, ibody);
    int sendLen = ihead + ibody;
    int ret = send(m_socket, sendBuf, sendLen, 0);

    return ret;
}

int MySocket::ReceiveData()
{
    std::string* redata = nullptr;
    sockaddr_in sin;
    int slen = sizeof(sin);
    char reBuf[SEND_DATA_LEN] = {0};
    int ret = recvfrom(m_socket, reBuf, SEND_DATA_LEN, 0, (sockaddr*)&sin, &slen);
    if (ret > 0) {
        Tcp_SendData* pData = (Tcp_SendData*)reBuf;
        //printf("%s\n", reBuf);
        OnSelectEvent.emit(pData);
    }
    return ret;

}

注意:

依赖的部分文件(.h,.cpp文件)见本专栏其他文章。

相关推荐
UestcXiye17 分钟前
《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列
c++·计算机网络·ip·tcp
霁月风1 小时前
设计模式——适配器模式
c++·适配器模式
弗锐土豆2 小时前
Windows系统中Oracle VM VirtualBox的安装
windows·虚拟机·virtualbox
秋の花2 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
jrrz08282 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
咖啡里的茶i2 小时前
Vehicle友元Date多态Sedan和Truck
c++
城南vision2 小时前
计算机网络——TCP篇
网络·tcp/ip·计算机网络
海绵波波1072 小时前
Webserver(4.9)本地套接字的通信
c++
@小博的博客2 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
爱吃喵的鲤鱼3 小时前
linux进程的状态之环境变量
linux·运维·服务器·开发语言·c++