socket 收发TCP/UDP

一、c++

个人测试记录,有问题还请指出,谢谢

参考:C++开发基础之网络编程WinSock库使用详解TCP/UDP Socket开发_c++ udp使用什么库-CSDN博客

代码中Logger测试见文章: c++中spdlog的使用/python中logger的使用-CSDN博客

1、main.cpp

收发TCP信号:

#include <iostream>
#include <thread>
#include <vector>

#include "Logger.h"
#include "SocketManager.h"

#pragma warning(disable:4996)

int main() {
	initLogger();
	SocketManager socket_manager;
	
	// 使用 std::thread 并传递成员函数的指针和对象实例的引用
	std::thread t1(&SocketManager::get_from_tcp, &socket_manager, 11100);
	// std::thread t2(&SocketManager::get_from_udp, &socket_manager, 11111);
	std::thread t3(&SocketManager::send_to_tcp, &socket_manager, "123456", "127.0.0.1", 11100);
	// std::thread t4(&SocketManager::send_to_udp, &socket_manager, "123456", "127.0.0.1", 11111);
	t1.detach();
	// t2.detach();
	t3.detach();
	// t4.detach();
	Sleep(6000000);
	return 0;
}

 运行结果如下:

 收发UDP信号:

#include <iostream>
#include <thread>
#include <vector>

#include "Logger.h"
#include "SocketManager.h"

#pragma warning(disable:4996)

int main() {
	initLogger();
	SocketManager socket_manager;
	
	// 使用 std::thread 并传递成员函数的指针和对象实例的引用
	// std::thread t1(&SocketManager::get_from_tcp, &socket_manager, 11100);
	std::thread t2(&SocketManager::get_from_udp, &socket_manager, 11111);
	// std::thread t3(&SocketManager::send_to_tcp, &socket_manager, "123456", "127.0.0.1", 11100);
	std::thread t4(&SocketManager::send_to_udp, &socket_manager, "123456", "127.0.0.1", 11111);
	// t1.detach();
	t2.detach();
	// t3.detach();
	t4.detach();
	Sleep(6000000);
	return 0;
}

 运行结果如下:

2、SocketManager.h

// #pragma once  // 为确保在不同编译环境中使用,可以使用#define的方法
#ifndef	SOCKETMANAGER_H
#define SOCKETMANAGER_H

#include <iostream>
#include <stdio.h>
#include <winsock2.h>
#include <string>
#include "Logger.h"

#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4996)

std::string asciiToHex(const std::string& asciiStr); // 将ascii码转为十六进制

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

	void initialization();  // 初始化套接字库
	void get_from_udp(int);   // 从客户端接收发来的udp信息
	void get_from_tcp(int); // 从客户端接收发来的tcp信息
	void send_to_tcp(std::string, std::string, int);  // 向服务端发送tcp信息
	void send_to_udp(std::string, std::string, int);  // 向服务端发送udp信息

private:
	//定义服务端套接字,接受请求套接字
	SOCKET ListenSocket_UDP_get;
	SOCKET ListenSocket_TCP_get;
	SOCKET SendSocket_UDP_to;
	SOCKET SendSocket_TCP_to;
	//服务端/客户端地址
	SOCKADDR_IN service_UDP_get;
	SOCKADDR_IN service_TCP_get;
	SOCKADDR_IN service_UDP_to;
	SOCKADDR_IN service_TCP_to;
};


#endif  // SOCKETMANAGER_H

3、SocketManager.cpp

#include "SocketManager.h"

SocketManager::SocketManager() {
	ListenSocket_UDP_get = INVALID_SOCKET;
	ListenSocket_TCP_get = INVALID_SOCKET;
	SendSocket_UDP_to = INVALID_SOCKET;
	SendSocket_TCP_to = INVALID_SOCKET;
}

SocketManager::~SocketManager() {
	if (ListenSocket_UDP_get != INVALID_SOCKET) {
		closesocket(ListenSocket_UDP_get);
		WSACleanup();
	}

	if (ListenSocket_TCP_get != INVALID_SOCKET) {
		closesocket(ListenSocket_TCP_get);
		WSACleanup();
	}

	if (SendSocket_UDP_to != INVALID_SOCKET) {
		closesocket(SendSocket_UDP_to);
		WSACleanup();
	}

	if (SendSocket_TCP_to != INVALID_SOCKET) {
		closesocket(SendSocket_TCP_to);
		WSACleanup();
	}
}


void SocketManager::get_from_udp(int port) {
	// 初始化套接字库
	initialization();
	// 创建套接字
	ListenSocket_UDP_get = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (ListenSocket_UDP_get == INVALID_SOCKET) {
		logger->error("创建套接字失败:" + WSAGetLastError());
		std::cout << "创建套接字失败:"<< WSAGetLastError() << std::endl;
		WSACleanup();
		exit(0);
	}

	//填充服务端信息
	service_UDP_get.sin_family = AF_INET;  // 设置地址族为 IPv4
	service_UDP_get.sin_addr.s_addr = INADDR_ANY;  // 将 IP 地址设置为 0.0.0.0,表示绑定到所有本地 IP 地址
	service_UDP_get.sin_port = htons(port);   // 将端口号转换为网络字节序,并设置为指定的端口号

	// 绑定套接字
	if (bind(ListenSocket_UDP_get, (SOCKADDR*)&service_UDP_get, sizeof(service_UDP_get)) == SOCKET_ERROR)
	{
		logger->error("绑定套接字失败: " + WSAGetLastError());
		std::cout << "绑定套接字失败: " + WSAGetLastError() << std::endl;
		closesocket(ListenSocket_UDP_get);
		WSACleanup();
		exit(0);
	}


	char recvbuf[512];  // 定义接收信息的缓冲区,大小为512字节
	int iRecvResult;  // 存储接收操作的返回结果
	sockaddr_in clientAddr;   // 用于存储客户端的地址信息
	int iAddrLen = sizeof(clientAddr);  // 存储地址结构体的大小
	do
	{	
		std::cout << "服务端正在等待数据发送,请稍候...." << std::endl;
		// 接收来自客户端的数据
		iRecvResult = recvfrom(ListenSocket_UDP_get, recvbuf, sizeof(recvbuf), 0, (SOCKADDR*)&clientAddr, &iAddrLen);
		// std::cout << iRecvResult << std::endl;
		// 检查接收操作是否成功
		if (iRecvResult > 0)
		{
			std::string result(recvbuf, iRecvResult);
			std::cout << "收到信息:" + result << std::endl;
			logger->info("收到信息:" + result);
			
			// 将接收到的数据发送回客户端
			// sendto(ListenSocket_UDP, recvbuf, iRecvResult, 0, (SOCKADDR*)&clientAddr, sizeof(clientAddr));
		}
		else if (iRecvResult == 0)
		{
			std::cout << "连接关闭" << std::endl;
			logger->info("连接关闭");
		}
		else
		{
			std::cout << "接受信息失败:" << WSAGetLastError() << std::endl;
			logger->error("接受信息失败:" + WSAGetLastError());
			closesocket(ListenSocket_UDP_get);
			WSACleanup();
		}

	} while (iRecvResult > 0);

	closesocket(ListenSocket_UDP_get);
	WSACleanup();
}


void SocketManager::initialization() {
	//初始化套接字库
	WORD w_req = MAKEWORD(2, 2);//版本号
	WSADATA wsadata;
	int err;
	err = WSAStartup(w_req, &wsadata);
	if (err != 0) {
		std::cout << "初始化套接字库失败!" << std::endl;
	}
	//检测版本号
	if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
		std::cout << "套接字库版本号不符!" << std::endl;
		WSACleanup();
	}
	//填充服务端地址信息
}


void SocketManager::send_to_tcp(std::string str, std::string ip, int port) {
	int send_len = 0;
	// 初始化套接字库
	initialization();
	//填充服务端信息
	service_TCP_to.sin_family = AF_INET;
	service_TCP_to.sin_addr.S_un.S_addr = inet_addr(ip.c_str());
	service_TCP_to.sin_port = htons(port);
	//创建套接字
	SendSocket_TCP_to = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (SendSocket_TCP_to == INVALID_SOCKET) {
		logger->error("创建套接字失败:" + WSAGetLastError());
		std::cout << "创建套接字失败:" << WSAGetLastError() << std::endl;
		WSACleanup();
		exit(1);
	}
	if (connect(SendSocket_TCP_to, (SOCKADDR*)&service_TCP_to, sizeof(SOCKADDR)) == SOCKET_ERROR) {
		std::cout << "服务器连接失败:" << WSAGetLastError() << std::endl;
		logger->error("服务器连接失败:" + WSAGetLastError());
		WSACleanup();
		exit(1);
	}
	// 发送信息
	send_len = send(SendSocket_TCP_to, str.c_str(), str.size(), 0);
	if (send_len < 0) {
		std::cout << "发送失败:" << WSAGetLastError() << std::endl;
		logger->error("发送失败:" + WSAGetLastError());
	}
	std::cout << send_len << "发送成功" << std::endl;
	//关闭套接字
	//closesocket(SendSocket_TCP_to);
	//释放DLL资源
	//WSACleanup();
}


void SocketManager::get_from_tcp(int port) {
	// 初始化套接字库
	initialization();
	// 创建套接字
	ListenSocket_TCP_get = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);   // tcp与udp之间有所不同
	if (ListenSocket_TCP_get == INVALID_SOCKET) {
		logger->error("创建套接字失败:" + WSAGetLastError());
		std::cout << "创建套接字失败:" << WSAGetLastError() << std::endl;
		WSACleanup();
		exit(1);
	}

	//填充服务端信息
	service_TCP_get.sin_family = AF_INET;  // 设置地址族为 IPv4
	service_TCP_get.sin_addr.s_addr = INADDR_ANY;  // 将 IP 地址设置为 0.0.0.0,表示绑定到所有本地 IP 地址
	service_TCP_get.sin_port = htons(port);   // 将端口号转换为网络字节序,并设置为指定的端口号

	// 绑定套接字
	if (bind(ListenSocket_TCP_get, (SOCKADDR*)&service_TCP_get, sizeof(service_TCP_get)) == SOCKET_ERROR)
	{
		logger->error("绑定套接字失败: " + WSAGetLastError());
		std::cout << "绑定套接字失败: " + WSAGetLastError() << std::endl;
		closesocket(ListenSocket_TCP_get);
		WSACleanup();
		exit(1);
	}


	char recvbuf[512];  // 定义接收信息的缓冲区,大小为512字节
	int iRecvResult;  // 存储接收操作的返回结果
	int len = 0;

	//设置套接字为监听状态
	if (listen(ListenSocket_TCP_get, SOMAXCONN) < 0) {
		std::cout << "设置监听状态失败:" << WSAGetLastError() << std::endl;
		logger->error("设置监听状态失败:" + WSAGetLastError());
		WSACleanup();
	}
	std::cout << "服务端正在监听连接,请稍候...." << std::endl;
	len = sizeof(service_TCP_get);
	SOCKET ClientSocket = INVALID_SOCKET;  // 初始化 ClientSocket 变量并将其设置为无效的套接字
	
	do
	{
		std::cout << "服务端正在等待数据发送,请稍候...." << std::endl;
		ClientSocket = accept(ListenSocket_TCP_get, (SOCKADDR*)&service_TCP_get, &len); // 等待客户端连接请求并接受连接
		/*
		accept 函数会阻塞,直到有客户端连接请求到达,然后返回一个新的套接字
        ListenSocket_TCP_get 是服务器监听的套接字
        service_TCP_get 是用于存储客户端地址信息的结构体
        len 是地址结构体的大小,accept 函数调用时会被更新为实际的地址大小
		*/
		// std::cout << ClientSocket << std::endl;
		if (ClientSocket == SOCKET_ERROR) {
			std::cout << "算法端连接失败:" + WSAGetLastError() << std::endl;
			logger->error("算法端连接失败:" + WSAGetLastError());
			WSACleanup();
			exit(2);
		}
		// 接收来自客户端的数据
		iRecvResult = recv(ClientSocket, recvbuf, sizeof(recvbuf), 0);
		// 检查接收操作是否成功
		if (iRecvResult > 0)
		{
			// std::cout << iRecvResult << std::endl;
			std::string result(recvbuf, iRecvResult);
			std::cout << "收到信息:" + result << std::endl;
			logger->info("收到信息:" + result);

			// 将接收到的数据发送回客户端
			// sendto(ListenSocket_UDP, recvbuf, iRecvResult, 0, (SOCKADDR*)&clientAddr, sizeof(clientAddr));
		}
		else if (iRecvResult == 0)
		{
			std::cout << "连接关闭" << std::endl;
			logger->info("连接关闭");
		}
		else
		{
			std::cout << "接受信息失败:" << WSAGetLastError() << std::endl;
			logger->error("接受信息失败:" + WSAGetLastError());
			closesocket(ListenSocket_UDP_get);
			WSACleanup();
		}
	} while (iRecvResult > 0);

	closesocket(ListenSocket_TCP_get);
	WSACleanup();
}


void SocketManager::send_to_udp(std::string str, std::string ip, int port) {
	int send_len = 0;
	// 初始化套接字库
	initialization();
	//填充服务端信息
	service_UDP_to.sin_family = AF_INET;
	service_UDP_to.sin_addr.S_un.S_addr = inet_addr(ip.c_str());
	service_UDP_to.sin_port = htons(port);
	//创建套接字
	SendSocket_UDP_to = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (SendSocket_UDP_to == INVALID_SOCKET) {
		logger->error("创建套接字失败:" + WSAGetLastError());
		std::cout << "创建套接字失败:" << WSAGetLastError() << std::endl;
		WSACleanup();
		exit(0);
	}
	int iSendResult = sendto(SendSocket_UDP_to, str.c_str(), str.size(), 0, (SOCKADDR*)&service_UDP_to, sizeof(service_UDP_to));
	if (iSendResult == SOCKET_ERROR) {
		std::cout << "发送失败:" << WSAGetLastError() << std::endl;
		logger->error("发送失败:" + WSAGetLastError());
	}
	//关闭套接字
	closesocket(SendSocket_UDP_to);
	//释放DLL资源
	WSACleanup();
}


std::string asciiToHex(const std::string& asciiStr) {
    std::string hexStr;
    for (char c : asciiStr) {
        unsigned char value = static_cast<unsigned char>(c);
        hexStr += std::to_string(static_cast<int>(value >> 4)) + std::to_string(static_cast<int>(value & 0x0F));
    }
    return hexStr;
}

相关推荐

  1. tcpudp面试题

    2024-07-20 22:14:01       31 阅读
  2. Socket通信

    2024-07-20 22:14:01       58 阅读
  3. Socket函数

    2024-07-20 22:14:01       52 阅读
  4. epoll_socket

    2024-07-20 22:14:01       56 阅读
  5. socket编程

    2024-07-20 22:14:01       50 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-20 22:14:01       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-20 22:14:01       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-20 22:14:01       45 阅读
  4. Python语言-面向对象

    2024-07-20 22:14:01       55 阅读

热门阅读

  1. SharedPreferences 和 MMKV 是何方神圣

    2024-07-20 22:14:01       18 阅读
  2. 力扣1942.最小未被占据椅子的编号

    2024-07-20 22:14:01       16 阅读
  3. linux LED代码设计

    2024-07-20 22:14:01       19 阅读
  4. 【深度学习图像】拼接图的切分

    2024-07-20 22:14:01       16 阅读
  5. dp算法第三天(暑期提升)

    2024-07-20 22:14:01       20 阅读
  6. RabbitMQ 全面解析与常见问题解答

    2024-07-20 22:14:01       18 阅读
  7. 关于大数据技术栈的一些总结

    2024-07-20 22:14:01       17 阅读
  8. 酒茶元宇宙:探索科技与传统文化的融合

    2024-07-20 22:14:01       12 阅读
  9. 移动支付行业现状及其特点

    2024-07-20 22:14:01       17 阅读
  10. Kubernetes v1.30:只读卷挂载可以实现只读了

    2024-07-20 22:14:01       18 阅读
  11. Unity运行时节点编辑器——互动电影案例

    2024-07-20 22:14:01       18 阅读
  12. flask渲染页码

    2024-07-20 22:14:01       17 阅读