添加一个TCP示例和一个Curl下载文件示例

This commit is contained in:
taynpg 2024-03-08 15:27:17 +08:00
parent 4ca30574a9
commit 54310e4b29
10 changed files with 658 additions and 0 deletions

View File

@ -0,0 +1,86 @@
#include <iostream>
#include <bitset>
#include <cstring>
// 问题:将一个二进制流转换成可阅读的字符串,字符串为:大写字母加数字,去除0和O,I和1相近字符。
const int g_bitNum = 5;
const char* g_Coder = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
int Encode(const char* pData, int nLen, char* res)
{
int totalLen = nLen * 8;
int resLen = totalLen / g_bitNum;
if (totalLen % g_bitNum != 0) ++resLen;
if (res == nullptr) {
return resLen;
}
for (int i = 0; i < resLen; ++i) {
unsigned char nIndex = 0;
int index = i * g_bitNum;
for (int j = 0; j < g_bitNum && index + j < totalLen; ++j) {
// bitValue 这一行只管取出下一位的值,放在哪里不管。
// index 是连续的(相当于大组里面内增,换个大组继续内增)
// index / 8 或者 index % 8 就是锁定第几组char的第几个,移动到最低位取出。
unsigned char bitValue = ((pData[index / 8] >> (7 - index % 8)) & 1);
// value 这一行只管把值放到对应的位置,与上面不要联系。
// 这里对 value 高位到低位的放
nIndex |= (bitValue << (g_bitNum - 1 - j));
// 关键点:value 和 bitValue 各管各的。
++index;
}
res[i] = g_Coder[nIndex];
}
res[resLen] = '\0';
return resLen;
}
int Decode(const char* pData, unsigned char* res)
{
int len = static_cast<int>(std::strlen(pData));
int codeBitCount = len * g_bitNum;
int resCnt = codeBitCount / 8;
if (res == nullptr) {
return resCnt;
}
std::memset(res, 0, resCnt * sizeof(char));
for (int i = 0; i < len; ++i) {
const char key = pData[i];
int nIndex = static_cast<int>(std::strchr(g_Coder, key) - g_Coder);
for (int j = 0; j < g_bitNum && i * g_bitNum + j < codeBitCount; ++j) {
// bitValue 这一行,只管取出每一位
int bitValue = ((nIndex >> (g_bitNum - 1 - j)) & 1);
// nOffset 是原始数据位索引
int nOffset = i * g_bitNum + j;
res[nOffset / 8] |= (bitValue << (7 - nOffset % 8));
}
}
return resCnt;
}
int main()
{
int data[] = {12345, 45678};
std::cout << "Original Data Len: " << sizeof(data) << std::endl;
char* szEncode = nullptr;
int size = Encode((const char*)data, sizeof(data), szEncode);
std::printf("Encode Data Len: %d\n", size);
szEncode = new char[size + 1];
Encode((const char*)data, sizeof(data), szEncode);
std::printf("Encode Data: %s\n", szEncode);
unsigned char * szDecode = nullptr;
int osize = Decode((const char *)szEncode, szDecode);
std::printf("Decode Data Len: %d\n", osize);
szDecode = new unsigned char [osize + 1];
Decode((const char*)szEncode, szDecode);
int* pInt = (int *)szDecode;
std::printf("Int[0]:%d, Int[1]:%d\n", pInt[0], pInt[1]);
delete[] szDecode;
delete[] szEncode;
return 0;
}

View File

@ -0,0 +1,6 @@
cmake_minimum_required (VERSION 3.8)
project (cppNetTool)
set(CMAKE_CXX_STANDARD 11)
add_executable(cppNetTool main.cpp multi_thread_down.cpp)
target_link_libraries(cppNetTool curl)

9
cpp/demo/net/main.cpp Normal file
View File

@ -0,0 +1,9 @@
#include <iostream>
#include "multi_thread_down.h"
int main(int argc, const char* argv[])
{
CThreadDownload downloader;
downloader.download(argv[1], argv[2]);
return 0;
}

View File

@ -0,0 +1,93 @@
#include "multi_thread_down.h"
void CTimer::start()
{
m_start = std::chrono::high_resolution_clock::now();
}
size_t CTimer::getTime()
{
m_end = std::chrono::high_resolution_clock::now();
std::chrono::milliseconds duration = std::chrono::duration_cast<std::chrono::milliseconds>(m_end - m_start);
size_t cnt = duration.count();
return cnt;
}
CThreadDownload::CThreadDownload()
= default;
CThreadDownload::~CThreadDownload()
= default;
double CThreadDownload::getFileLength(const char* url)
{
double len = 0;
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
if (curl_easy_perform(curl) == CURLE_OK) {
curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &len);
}
else {
len = -1;
}
curl_easy_cleanup(curl);
return len;
}
int CThreadDownload::download(const char* url, const char* filename) {
double fileLen = getFileLength(url);
if (fileLen < 0) {
std::printf("Failed to obtain the file size!");
return -1;
}
std::ofstream stream(filename, std::ios::binary | std::ios::trunc);
if (!stream.is_open()) {
std::printf("Open File Failed: %s", filename);
return -1;
}
m_fstream = std::move(stream);
std::printf("File Len: %lf\n", fileLen);
// try
// {
// m_fstream.seekp(fileLen - 1);
// }
// catch(const std::exception& e)
// {
// std::cerr << e.what() << '\n';
// m_fstream.close();
// return -1;
// }
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunCall);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
// 建立TCP连接,发送http请求,等待数据返回
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::printf("res: %d\n", res);
}
curl_easy_cleanup(curl);
m_fstream.close();
std::cout << "Done." << std::endl;
return 0;
}
size_t CThreadDownload::writeFunCall(void* ptr, size_t size, size_t mmb, void* userdata)
{
size_t nSize = size * mmb;
CThreadDownload* pDown = (CThreadDownload*)userdata;
pDown->m_fstream.write((const char*)ptr, nSize);
std::printf("writeFunCall: %ld\n", nSize);
return nSize;
}

View File

@ -0,0 +1,38 @@
#ifndef MULTI_DOWNLOAD_H
#define MULTI_DOWNLOAD_H
#include <curl/curl.h>
#include <iostream>
#include <fstream>
#include <chrono>
class CTimer
{
using time_point_t = std::chrono::high_resolution_clock::time_point;
public:
CTimer() = default;
~CTimer() = default;
public:
void start();
// 秒种
size_t getTime();
private:
time_point_t m_start;
time_point_t m_end;
};
class CThreadDownload
{
public:
CThreadDownload();
~CThreadDownload();
public:
double getFileLength(const char* url);
int download(const char* url, const char* filename);
static size_t writeFunCall(void* ptr, size_t size, size_t mmb, void* userdata);
private:
std::ofstream m_fstream;
};
#endif

View File

@ -0,0 +1,31 @@
{
"files.autoSave": "onFocusChange",
"editor.fontSize": 14,
"editor.fontFamily": "'Cascadia Code', 'Cascadia Code', 'Cascadia Code'",
"cmake.configureOnOpen": true,
"cmake.debugConfig": {
//"externalConsole": true,
"setupCommands": [
{
"description": "-gdb-set charset utf-8",
"text": "-gdb-set charset UTF-8"
},
{
"description": "Enable gdb pretty-printing",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
"editor.inlayHints.enabled": "off",
"C_Cpp.intelliSenseEngine": "disabled",
"clangd.arguments": [
"--clang-tidy",
"-j=4",
"--pch-storage=memory",
"--compile-commands-dir=build",
"--background-index",
"--ranking-model=heuristics",
"--query-driver=E:/program/mingw64/bin/g++.exe"
]
}

View File

@ -0,0 +1,11 @@
cmake_minimum_required (VERSION 3.8)
project (tcpfilesend)
set(CMAKE_CXX_STANDARD 11)
add_executable(tcpfilesend main.cpp)
add_executable(tcpfileserver server.cpp)
add_executable(tcpfileserver2 server2.cpp)
target_link_libraries(tcpfilesend ws2_32)
target_link_libraries(tcpfileserver ws2_32)
target_link_libraries(tcpfileserver2 ws2_32)

View File

@ -0,0 +1,89 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <chrono>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <thread>
constexpr int BUFFER_SIZE = 4096;
int main(int argc, char** argv)
{
if (argc == 1) {
std::cout << "Need Param, Example: send 127.0.0.1 9696 E:\\2.bmp\n";
return 0;
}
// 初始化Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "Failed to initialize Winsock." << std::endl;
return 1;
}
// 创建套接字
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Failed to create socket." << std::endl;
WSACleanup();
return 1;
}
// 设置服务器地址
sockaddr_in serverAddress{};
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(std::stoi(std::string(argv[2])));
if (inet_pton(AF_INET, argv[1], &(serverAddress.sin_addr)) <= 0) {
std::cerr << "Invalid server address." << std::endl;
closesocket(clientSocket);
WSACleanup();
return 1;
}
// 连接到服务器
if (connect(clientSocket, reinterpret_cast<sockaddr*>(&serverAddress),
sizeof(serverAddress)) == SOCKET_ERROR) {
std::cerr << "Failed to connect to server." << std::endl;
closesocket(clientSocket);
WSACleanup();
return 1;
}
// 打开要发送的文件
FILE* file = std::fopen(argv[3], "rb");
if (!file) {
std::cerr << "Failed to open file : " << argv[3] << std::endl;
closesocket(clientSocket);
WSACleanup();
return 1;
}
int Second = 3;
std::cout << Second << " Second after to start send .....\n";
std::this_thread::sleep_for(std::chrono::milliseconds(Second * 1000));
// 读取文件内容并发送到服务器
size_t allLen = 0;
char buffer[BUFFER_SIZE];
while (!std::feof(file)) {
int nSize = std::fread(buffer, sizeof(char), BUFFER_SIZE, file);
if (nSize > 0) {
allLen += nSize;
if (send(clientSocket, buffer, nSize, 0) == SOCKET_ERROR) {
std::cerr << "Failed to send data to server." << std::endl;
break;
}
std::cout << "already send Size = " << allLen << "\n";
}
}
// 关闭套接字和文件
std::fclose(file);
closesocket(clientSocket);
WSACleanup();
std::cout << "Send Done, Size = " << allLen << std::endl;
return 0;
}

View File

@ -0,0 +1,170 @@
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
#define BUFFER_SIZE 1024
int main(int argc, char** argv)
{
if (argc == 1) {
std::cout << "Need Param, Example: server 127.0.0.1 9696 E:\\2.bmp\n";
return 0;
}
// 初始化 Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "Failed to initialize Winsock." << std::endl;
return 1;
}
// 创建套接字
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Failed to create socket: " << WSAGetLastError()
<< std::endl;
WSACleanup();
return 1;
}
// 绑定地址和端口
sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(std::stoi(std::string(argv[2])));
serverAddr.sin_addr.s_addr = inet_addr(argv[1]);
;
if (bind(serverSocket, reinterpret_cast<sockaddr*>(&serverAddr),
sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Failed to bind socket: " << WSAGetLastError()
<< std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 监听连接请求
if (listen(serverSocket, 1) == SOCKET_ERROR) {
std::cerr << "Failed to listen on socket: " << WSAGetLastError()
<< std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "server ip: " << argv[1] << " port: " << argv[2] << std::endl;
std::cout << "Server started. Waiting for client connection..."
<< std::endl;
// 接受客户端连接
SOCKET clientSocket = accept(serverSocket, nullptr, nullptr);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Failed to accept client connection: " << WSAGetLastError()
<< std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "Client connected. Receiving data..." << std::endl;
// 创建接收缓冲区
char buffer[BUFFER_SIZE];
size_t allLen = 0;
// 打开文件以保存接收的数据
FILE* file = std::fopen(argv[3], "wb");
if (!file) {
std::cerr << "Failed to open file for writing." << std::endl;
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 循环接收数据
while (true) {
// 创建事件对象
WSAEVENT event = WSACreateEvent();
if (event == WSA_INVALID_EVENT) {
std::cerr << "Failed to create event: " << WSAGetLastError()
<< std::endl;
break;
}
// 将事件对象与套接字关联
if (WSAEventSelect(clientSocket, event, FD_READ) == SOCKET_ERROR) {
std::cerr << "Failed to associate event with socket: "
<< WSAGetLastError() << std::endl;
WSACloseEvent(event);
break;
}
// 等待事件对象变为 signaled 状态
DWORD waitResult =
WSAWaitForMultipleEvents(1, &event, FALSE, WSA_INFINITE, FALSE);
if (waitResult == WSA_WAIT_FAILED) {
std::cerr << "Failed to wait for event: " << WSAGetLastError()
<< std::endl;
WSACloseEvent(event);
break;
}
// 检查事件对象状态
if (waitResult == WSA_WAIT_EVENT_0) {
WSANETWORKEVENTS networkEvents;
if (WSAEnumNetworkEvents(clientSocket, event, &networkEvents) ==
SOCKET_ERROR) {
std::cerr << "Failed to enumerate network events: "
<< WSAGetLastError() << std::endl;
WSACloseEvent(event);
break;
}
// 检查是否有数据可读
if (networkEvents.lNetworkEvents & FD_READ) {
if (networkEvents.iErrorCode[FD_READ_BIT] != 0) {
std::cerr << "Error in FD_READ: "
<< networkEvents.iErrorCode[FD_READ_BIT]
<< std::endl;
WSACloseEvent(event);
break;
}
// 接收数据
int bytesRead = recv(clientSocket, buffer, BUFFER_SIZE, 0);
if (bytesRead > 0) {
// 将数据写入文件
std::fwrite(buffer, sizeof(char), bytesRead, file);
allLen += bytesRead;
std::cout << "already recv: " << allLen << "\n";
} else if (bytesRead == 0) {
// 客户端关闭连接
std::cout << "Client disconnected." << std::endl;
WSACloseEvent(event);
break;
} else {
// 发生错误
std::cerr << "Failed to receive data: " << WSAGetLastError()
<< std::endl;
WSACloseEvent(event);
break;
}
}
}
WSACloseEvent(event);
}
// 关闭套接字和清理资源
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
std::fclose(file);
std::cout << "Done .... file: " << argv[3] << std::endl;
return 0;
}

View File

@ -0,0 +1,125 @@
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
#define BUFFER_SIZE 1024
int main(int argc, char** argv)
{
if (argc == 1) {
std::cout << "Need Param, Example: server 127.0.0.1 9696 E:\\2.bmp\n";
return 0;
}
// 初始化 Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "Failed to initialize Winsock." << std::endl;
return 1;
}
// 创建套接字
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Failed to create socket: " << WSAGetLastError()
<< std::endl;
WSACleanup();
return 1;
}
// 绑定地址和端口
sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(std::stoi(std::string(argv[2])));
serverAddr.sin_addr.s_addr = inet_addr(argv[1]);
;
if (bind(serverSocket, reinterpret_cast<sockaddr*>(&serverAddr),
sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Failed to bind socket: " << WSAGetLastError()
<< std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 监听连接请求
if (listen(serverSocket, 1) == SOCKET_ERROR) {
std::cerr << "Failed to listen on socket: " << WSAGetLastError()
<< std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "server ip: " << argv[1] << " port: " << argv[2] << std::endl;
std::cout << "Server started. Waiting for client connection..."
<< std::endl;
// 接受客户端连接
SOCKET clientSocket = accept(serverSocket, nullptr, nullptr);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Failed to accept client connection: " << WSAGetLastError()
<< std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "Client connected. Receiving data..." << std::endl;
// 创建接收缓冲区
char buffer[BUFFER_SIZE];
size_t allLen = 0;
// 打开文件以保存接收的数据
FILE* file = std::fopen(argv[3], "wb");
if (!file) {
std::cerr << "Failed to open file for writing." << std::endl;
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 循环接收数据
while (true) {
WSABUF dataBuffer{};
dataBuffer.len = BUFFER_SIZE;
dataBuffer.buf = buffer;
DWORD bytesReceived = 0;
DWORD flags = 0;
// 接收数据
if (WSARecv(clientSocket, &dataBuffer, 1, &bytesReceived, &flags,
nullptr, nullptr) == SOCKET_ERROR) {
std::cerr << "Failed to receive data: " << WSAGetLastError()
<< std::endl;
break;
}
// 检查接收到的数据大小
if (bytesReceived > 0) {
// 将数据写入文件
// 将数据写入文件
std::fwrite(buffer, sizeof(char), bytesReceived, file);
allLen += bytesReceived;
std::cout << "already recv: " << allLen << "\n";
} else if (bytesReceived == 0) {
// 客户端关闭连接
std::cout << "Client disconnected." << std::endl;
break;
}
}
// 关闭套接字和清理资源
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
std::fclose(file);
return 0;
}