c++ 通过socket编写HttpClient

编码转换



//UNICODE 转为 ASCII 
string WCHAR_TO_ACSII(wstring& strWide)
{
    int asciisize = ::WideCharToMultiByte(CP_OEMCP, 0, strWide.c_str(), -1, NULL, 0, NULL, NULL);
    if (asciisize == ERROR_NO_UNICODE_TRANSLATION)
    {
        throw std::exception("Invalid UTF-8 sequence.");
    }
    if (asciisize == 0)
    {
        throw std::exception("Error in conversion.");
    }
    std::vector<char> resultstring(asciisize);
    int convresult = ::WideCharToMultiByte(CP_OEMCP, 0, strWide.c_str(), -1, &resultstring[0], asciisize, NULL, NULL);
    if (convresult != asciisize)
    {
        throw std::exception("La falla!");
    }
    return std::string(&resultstring[0]);
}

//ASCII 转 UNICODE 
wstring ACSII_TO_WCHAR(string& strAscii)
{
    int widesize = MultiByteToWideChar(CP_ACP, 0, (char*)strAscii.c_str(), -1, NULL, 0);
    if (widesize == ERROR_NO_UNICODE_TRANSLATION) {
        throw std::exception("Invalid UTF-8 sequence.");
    }
    if (widesize == 0)
    {
        throw std::exception("Error in conversion.");
    }
    std::vector<wchar_t> resultstring(widesize);
    int convresult = MultiByteToWideChar(CP_ACP, 0, (char*)strAscii.c_str(), -1, &resultstring[0], widesize);
    if (convresult != widesize)
    {
        throw std::exception("La falla!");
    }
    return std::wstring(&resultstring[0]);
}

//UNICODE 转 UTF8 
std::string UNICODE_TO_UTF8(const std::wstring& strUnicode)
{
    int utf8size = ::WideCharToMultiByte(CP_UTF8, 0, strUnicode.c_str(), -1, NULL, 0, NULL, NULL);
    if (utf8size == 0)
    {
        throw std::exception("Error in conversion.");
    }
    std::vector<char> resultstring(utf8size);
    int convresult = ::WideCharToMultiByte(CP_UTF8, 0, strUnicode.c_str(), -1, &resultstring[0], utf8size, NULL, NULL);
    if (convresult != utf8size)
    {
        throw std::exception("La falla!");
    }
    return std::string(&resultstring[0]);
}

//UTF-8 转 UNICODE 
std::wstring UTF8_TO_UNICODE(const std::string& strUtf8)
{
    int widesize = ::MultiByteToWideChar(CP_UTF8, 0, strUtf8.c_str(), -1, NULL, 0);
    if (widesize == ERROR_NO_UNICODE_TRANSLATION) {
        throw std::exception("Invalid UTF-8 sequence.");
    }
    if (widesize == 0)
    {
        throw std::exception("Error in conversion.");
    }
    std::vector<wchar_t> resultstring(widesize);
    int convresult = ::MultiByteToWideChar(CP_UTF8, 0, strUtf8.c_str(), -1, &resultstring[0], widesize);
    if (convresult != widesize)
    {
        throw std::exception("La falla!");
    }
    return std::wstring(&resultstring[0]);
}

//ASCII 转 UTF8 
string ASCII_TO_UTF8(string& strAscii)
{
    string strRet("");
    wstring wstr = ACSII_TO_WCHAR(strAscii);
    strRet = UNICODE_TO_UTF8(wstr);
    return strRet;
}

//UTF-8 转 ASCII 
string UTF8_TO_ASCII(string& strUtf8)
{
    string strRet("");
    wstring wstr = UTF8_TO_UNICODE(strUtf8);
    strRet = WCHAR_TO_ACSII(wstr);
    return strRet;
}



HttpClient头文件

#pragma once
#include 
#include 
#include 
#include 
#include 
#include 

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

const int BUFFER_SIZE = 4096;

class HttpClient
{
public:
	HttpClient();
	~HttpClient();

	void SetHost(const std::string& host);
	void SetPort(const int& port);
	void SetPath(const std::string& path);

	std::string GetHost() const;
	int  GetPort() const;
	std::string GetPath() const;

	void SetUrl(const std::string& host, const int& port, const std::string& path);
	void SetUrl(const std::string& url);

	std::string SetRequestParameter(const std::string& content, const std::string& contentType = "text/xml;charset=utf-8");

	std::string PostRequest(const std::string& request);

	static std::string PostRequestThread(const std::string& host, const int& port, const std::string& request);
private:
	std::string m_sHost;
	int			m_nPort;
	std::string m_sPath;
	
};


HttpClient源文件

#include "HttpClient.h"
#include 

#define USE_FIONBIO_MODE

HttpClient::HttpClient()
{
	m_sHost = "";
	m_nPort = 0;
	m_sPath = "";
}

HttpClient::~HttpClient()
{
}

void HttpClient::SetHost(const std::string& host)
{
	m_sHost = host;
}

void HttpClient::SetPort(const int& port)
{
	m_nPort = port;
}

void HttpClient::SetPath(const std::string& path)
{
	m_sPath = path;
}

std::string HttpClient::GetHost() const
{
	return std::string(m_sHost);
}

int HttpClient::GetPort() const
{
	return m_nPort;
}

std::string HttpClient::GetPath() const
{
	return std::string(m_sPath);
}

void HttpClient::SetUrl(const std::string& host, const int& port, const std::string& path)
{
	m_sHost = host;
	m_nPort = port;
	m_sPath = path;
}

void HttpClient::SetUrl(const std::string& url)
{
    std::string sUrl = url;

    // 查找 "http://" 或 "https://"
    size_t protocolPos = sUrl.find("://");
    if (protocolPos == std::string::npos) 
    {
        return;
    }

    // 提取协议部分并截取 URL
    std::string protocol = sUrl.substr(0, protocolPos);
    std::string remainingUrl = sUrl.substr(protocolPos + 3);  // 跳过协议名称和 "://"

    // 查找 IP 和端口
    size_t ipPos = remainingUrl.find("/");
    if (ipPos == std::string::npos) 
    {
        return;  
    }

    std::string ipAndPort = remainingUrl.substr(0, ipPos);

    // 分离 IP 和端口
    size_t portPos = ipAndPort.find(":");
    if (portPos != std::string::npos) 
    {
        m_sHost = ipAndPort.substr(0, portPos);
        m_nPort = std::atoi(ipAndPort.substr(portPos + 1).c_str());       
    }
    else 
    {
        m_sHost = ipAndPort;
        m_nPort = 0;
    }

    // 提取路径部分
    m_sPath = remainingUrl.substr(ipPos);

    std::cout << "======================================================" << std::endl;
    std::cout << "IP: " << m_sHost << std::endl;
    std::cout << "Port: " << m_nPort << std::endl;
    std::cout << "Path: " << m_sPath << std::endl;
    std::cout << "======================================================" << std::endl;
}

std::string HttpClient::SetRequestParameter(const std::string& content, const std::string& contentType)
{
	std::string sHeader =
		"POST " + m_sPath + " HTTP/1.1\r\n" +
		"Host: " + m_sHost + "\r\n" +
		"Content-Type: " + contentType + "\r\n" +
		"Content-Length: " + std::to_string(content.length()) + "\r\n" +
		"Connection: close\r\n" +
		"\r\n" + content;

	return std::string(sHeader);
}

std::string HttpClient::PostRequest(const std::string& request)
{
    // 初始化Winsock
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        std::cerr << "Failed to initialize Winsock." << std::endl;
        return "";
    }

    // 创建套接字
    SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == INVALID_SOCKET)
    {
        std::cerr << "Failed to create socket." << std::endl;
        WSACleanup();
        return "";
    }

    // 设置服务器地址
    sockaddr_in serverAddress{};
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(m_nPort);
    if (inet_pton(AF_INET, m_sHost.c_str(), &(serverAddress.sin_addr)) <= 0)
    {
        std::cerr << "Invalid address/Address not supported." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }

    int timeout = 2000;//ms
    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR ||
        setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR)
    {
        std::cerr << "setsockopt failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }

#ifdef USE_FIONBIO_MODE 
    //设置connect非阻塞方式连接
    unsigned long ul = 1;
    if (ioctlsocket(sockfd, FIONBIO, (unsigned long*)&ul) == SOCKET_ERROR)
    {
        std::cerr << "ioctlsocket failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }
    // 连接服务器(设为非阻塞等待)
    connect(sockfd, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
#else
    if (connect(sockfd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == SOCKET_ERROR)
    {
        std::cerr << "connect failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }
#endif
    
#ifdef USE_FIONBIO_MODE 
    //select 模型,设置connect超时
    struct timeval tagTimeout;
    fd_set _set;
    FD_ZERO(&_set);
    FD_SET(sockfd, &_set);
    int time = (timeout < 1000) ? 1 : timeout / 1000;
    tagTimeout.tv_sec = time; //连接超时时间(s)
    tagTimeout.tv_usec = 0;
    if (select(0, 0, &_set, 0, &tagTimeout) <= 0)
    {
        std::cerr << "Connection failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }
    // 设回阻塞模式
    unsigned long ul1 = 0;
    if (ioctlsocket(sockfd, FIONBIO, (unsigned long*)&ul1) == SOCKET_ERROR)
    {
        std::cerr << "Connection failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }
#endif

    // 发送请求
    if (send(sockfd, request.c_str(), request.length(), 0) == SOCKET_ERROR)
    {
        std::cerr << "Send request failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }

    // 接收响应
    char buffer[BUFFER_SIZE];
    std::string response;
    int nBytesRead;
    while ((nBytesRead = recv(sockfd, buffer, BUFFER_SIZE - 1, 0)) > 0)
    {
        response.append(buffer, nBytesRead);
        memset(buffer, 0, sizeof(buffer));
    }

    // 关闭套接字
    closesocket(sockfd);
    WSACleanup();

    return UTF8_TO_ASCII(response);
}


std::string HttpClient::PostRequestThread(const std::string& host, const int& port, const std::string& request)
{
    // 初始化Winsock
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        std::cerr << "Failed to initialize Winsock." << std::endl;
        return "";
    }

    // 创建套接字
    SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == INVALID_SOCKET)
    {
        std::cerr << "Failed to create socket." << std::endl;
        WSACleanup();
        return "";
    }

    // 设置服务器地址
    sockaddr_in serverAddress{};
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(port);
    if (inet_pton(AF_INET, host.c_str(), &(serverAddress.sin_addr)) <= 0)
    {
        std::cerr << "Invalid address/Address not supported." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }

    int timeout = 1000;//ms
    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR ||
        setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR)
    {
        std::cerr << "setsockopt failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }

#ifdef USE_FIONBIO_MODE 
    //设置connect非阻塞方式连接
    unsigned long ul = 1;
    if (ioctlsocket(sockfd, FIONBIO, (unsigned long*)&ul) == SOCKET_ERROR)
    {
        std::cerr << "ioctlsocket failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }
    // 连接服务器(设为非阻塞等待)
    connect(sockfd, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
#else
    if (connect(sockfd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == SOCKET_ERROR)
    {
        std::cerr << "connect failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }
#endif

#ifdef USE_FIONBIO_MODE 
    //select 模型,设置connect超时
    struct timeval tagTimeout;
    fd_set _set;
    FD_ZERO(&_set);
    FD_SET(sockfd, &_set);
    int time = (timeout < 1000) ? 1 : timeout / 1000;
    tagTimeout.tv_sec = time; //连接超时时间(s)
    tagTimeout.tv_usec = 0;
    if (select(0, 0, &_set, 0, &tagTimeout) <= 0)
    {
        std::cerr << "Connection failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }
    // 设回阻塞模式
    unsigned long ul1 = 0;
    if (ioctlsocket(sockfd, FIONBIO, (unsigned long*)&ul1) == SOCKET_ERROR)
    {
        std::cerr << "Connection failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }
#endif
    // 发送请求
    if (send(sockfd, request.c_str(), request.length(), 0) == SOCKET_ERROR)
    {
        std::cerr << "Send request failed." << std::endl;
        closesocket(sockfd);
        WSACleanup();
        return "";
    }

    // 接收响应
    char buffer[BUFFER_SIZE];
    std::string response;
    int nBytesRead;
    while ((nBytesRead = recv(sockfd, buffer, BUFFER_SIZE - 1, 0)) > 0)
    {
        response.append(buffer, nBytesRead);
        memset(buffer, 0, sizeof(buffer));
    }

    // 关闭套接字
    closesocket(sockfd);
    WSACleanup();

    return UTF8_TO_ASCII(response);
}

测试

int main()
{
    std::string xmlString = "这是xml数据";
    std::string slUrl = "http://192.168.1.115:1234/services/MyService?wsdl";


    HttpClient httpClient;
    
    //httpClient.SetUrl("192.168.1.115", 1234, "/services/MyService?wsdl");
    httpClient.SetUrl(slUrl);
    std::string request = httpClient.SetRequestParameter(xmlString);
    std::string response = httpClient.PostRequest(request);
    //std::string response = httpClient.PostRequestThread("10.30.35.116", 9005, request);

    //解析数据
	// ....

	//打印
    std::cout << "\nResponse:\n" << response << std::endl;

    getchar();
    return 0;
}

你可能感兴趣的:(C/C++,c++,vs)