首页 > 其他分享 >socket 收发TCP/UDP

socket 收发TCP/UDP

时间:2024-07-19 11:28:42浏览次数:17  
标签:std UDP socket get cout ListenSocket TCP SocketManager

一、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;
}

标签:std,UDP,socket,get,cout,ListenSocket,TCP,SocketManager
From: https://blog.csdn.net/Word_And_Me_/article/details/140542870

相关文章

  • TCP/IP协议,以及对等网络通信原理!
    TCP/IP模型协议分层应用层:HTTP:超文本传输协议(网站访问WEB)(Apache、nginx)(IIS)FTP:文件传输协议(网络文件传输)TFTP:简单文件传输协议(交换机和路由器重装)SMTP:简单邮件传输协议(发信)POP3:邮局协议3代(收信)SNMP:简单网络管理协议(服务器监控)DNS:域名系统(域名与IP解析)传输层:TCP:传......
  • 前端WebSocket的方法封装
    一、封装方法在项目根目录src下的utils中新增webSocketManager.js封装文件,代码内容如下://webSocketManager.js/**WebSocketMessenger封装类*/classWebSocketManager{constructor(url=null,userId=null,receiveMessageCallback=null){this.socket=nul......
  • npm/yarn/pnpm install失败:ERR_PNPM_NO_VERSIONS No versions available for uWebSock
    ERR_PNPM_NO_VERSIONS NoversionsavailableforuWebSockets.js.Thepackagemaybeunpublished.我在新项目中想要切换包管理器从yarn到pnpm的时候,删除node_modules和yarn.lock之后,pnpminstall竟然提示这个包可能没发布。我觉得这个不可能,都需要使用了,怎么可能没发......
  • 实现基于Spring Boot和WebSockets的实时通讯应用
    实现基于SpringBoot和WebSockets的实时通讯应用大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!实时通讯应用在现代互联网服务中越来越重要。使用WebSocket可以实现客户端和服务器之间的双向通讯,从而大大提高实时性。本文将介绍如何使用SpringBoot和Web......
  • WCHNET_SocketSend返回0x11原因及解决方法
    问题描述:TCPCLIENT模式使用WCHNET_SocketSend发送有概率会返回0x11按wchnet.h定义为内存溢出错误。异常分析:通过WCHNET_QueryUnack查看,发现异常时发送队列或缓冲区已经占满,导致再次发送时报发送内存溢出错误。 解决方法:如果项目对RAM需求不大,可适当将WCHNET_NUM_TCP_SE......
  • Socket、WebSocket 和 MQTT 的区别
    Socket协议定义:操作系统提供的网络通信接口,抽象了TCP/IP协议,支持TCP和UDP。特点:通用性:不限于Web应用,适用于各种网络通信。协议级别:直接使用TCP/UDP,需要手动管理连接和数据传输。实现复杂性:需要编写代码处理连接、数据传输和错误。使用场景:实时通信(聊天应用)、文件传输......
  • TCP协议详解
    传输控制协议(TCP,TransmissionControlProtocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。1.TCP头部格式源/目的端口:表示数据从哪个进程发送,然后发送到哪个进程去32位序列号:发送的数据按照一个字节一个编号存放进去32位确认号:用于给与对方响应,值为收到的TC......
  • udp 广播通信
    基于全网段广播的代码示例,要点主要有两个:(1)设置socket属性SO_BROADCAST(2)发送方添加广播255.255.255.255的路由,不然会产生“Networkisunreachable”错误iprouteadd255.255.255.255deveth0示例代码:#include<stdio.h>#include<string.h>#include<stdlib.h>#includ......
  • 在Linux中,tcp三次握⼿的过程及原理?
    在Linux中,TCP(传输控制协议)的三次握手是建立可靠连接的重要过程。这一机制确保了客户端和服务器之间能够安全、有序地交换数据。下面将详细阐述TCP三次握手的过程及原理:一、TCP三次握手的过程TCP三次握手过程涉及客户端(通常称为“主动打开方”)和服务器(通常称为“被动打开方”)之间......
  • 《UDP---FTP网络编程》
    UDP网络编程服务端(1)使用DatagramSocket创建socket,监听6666端口(2)使用DatagramPacket创建数据包(3)调用.receive()接收数据包(4)从数据包中读取数据**注意:使用String构造方法,将字节转换为原始的字符串(5)向客户端发送响应消息客户端(1)使用DatagramSo......