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文件)见本专栏其他文章。