【C++】TCP通信服务端与客户端代码实现及详解

这篇具有很好参考价值的文章主要介绍了【C++】TCP通信服务端与客户端代码实现及详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、服务端server实现

1. server代码

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <string>
#include <thread>

#pragma comment(lib, "ws2_32.lib")
#define PORT 65432

void Cleanup(SOCKET socket)
{
	closesocket(socket);
	WSACleanup();
}

void HandleClientCommunication(SOCKET clientSocket)
{
	std::cout << "成功和" << clientSocket << "建立连接!" << std::endl;

	while (true)
	{
		char buffer[1000];
		std::cout << "服务器向" << clientSocket << "发送数据:" << std::endl;
		std::cin.getline(buffer, sizeof(buffer));

		std::string message = buffer;
		int size = send(clientSocket, message.c_str(), static_cast<int>(message.length()), 0);
		if (message == "end")
		{
			std::cout << "关闭和" << clientSocket << "的连接!" << std::endl;
			break;
		}
		else if (size == SOCKET_ERROR || size == 0)
		{
			std::cout << "[发送信息失败] 错误代码:" << WSAGetLastError() << std::endl;
			break;
		}
		else
		{
			std::cout << "       [信息发送成功]" << std::endl;
		}

		memset(buffer, 0, sizeof(buffer));
		int receivedBytes = recv(clientSocket, buffer, sizeof(buffer), 0);
		if (receivedBytes == SOCKET_ERROR || receivedBytes == 0)
		{
			std::cout << clientSocket << "断开了连接!" << std::endl;
			break;
		}
		else
		{
			std::cout << clientSocket << "  说: " << buffer << std::endl;
		}
	}
	closesocket(clientSocket);
}

int main()
{
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		std::cout << "加载winsock.dll失败!" << std::endl;
		return 0;
	}

	SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (serverSocket == INVALID_SOCKET)
	{
		std::cout << "创建套接字失败!错误代码:" << WSAGetLastError() << std::endl;
		WSACleanup();
		return 0;
	}

	sockaddr_in serverAddress;
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_port = htons(PORT);
	inet_pton(AF_INET, "127.0.0.1", &serverAddress.sin_addr);

	if (bind(serverSocket, reinterpret_cast<SOCKADDR*>(&serverAddress), sizeof(serverAddress)) == SOCKET_ERROR)
	{
		std::cout << "地址绑定失败!错误代码:" << WSAGetLastError() << std::endl;
		Cleanup(serverSocket);
		return 0;
	}

	if (listen(serverSocket, 0) == SOCKET_ERROR)
	{
		std::cout << "监听失败!错误代码:" << WSAGetLastError() << std::endl;
		Cleanup(serverSocket);
		return 0;
	}

	while (true)
	{
		sockaddr_in clientAddress;
		int clientAddressSize = sizeof(clientAddress);
		SOCKET clientSocket = accept(serverSocket, reinterpret_cast<SOCKADDR*>(&clientAddress), &clientAddressSize);
		if (clientSocket != INVALID_SOCKET)
		{
			std::thread clientThread(HandleClientCommunication, clientSocket);
			clientThread.detach(); // 分离线程,不等待线程结束
		}
	}

	Cleanup(serverSocket);
	return 0;
}

2. 代码详解

上述代码使用Winsock库实现了简单的TCP服务器,它监听指定端口并与客户端进行通信。下面对代码进行详细分析:

  1. #pragma comment(lib, "ws2_32.lib") 是一个特殊的编译器指令,用于告诉编译器在链接阶段将 ws2_32.lib 库文件添加到最终的可执行文件中。无需在编译命令行或IDE中显式指定。这样做的好处是,可以将库文件的链接过程自动化,减少了手动操作的繁琐性,并确保在编译和链接过程中正确地使用所需的库文件。需要注意的是,该指令是特定于Microsoft Visual C++编译器的,并不是标准C++的一部分,因此在使用其他编译器时可能需要采用不同的方式来链接相应的库文件。

  2. Cleanup函数:该函数用于关闭套接字清理WSA(Winsock库)的资源。在程序退出前,应该调用该函数来进行善后处理。

    void Cleanup(SOCKET socket)
    {
    	closesocket(socket);   //关闭套接字
    	WSACleanup();          //清理WSA的资源
    }
    
  3. HandleClientCommunication函数:该函数在单独的线程中处理与客户端的通信。它首先向客户端发送数据,然后接收客户端的响应。如果接收到的消息是"end",表示客户端要求关闭连接,函数会退出循环并关闭套接字。

  4. main函数:程序的入口函数。它首先初始化Winsock库,创建一个套接字并绑定到指定的IP地址和端口。然后,服务器开始监听客户端连接请求。当有客户端连接时,将创建一个新的线程来处理与该客户端的通信。使用detach函数将线程分离,不等待线程结束。

  5. WSAStartup:初始化Ws2_32.dll动态链接库,指定winsock2.2版本,在使用socket之前,一定要初始化该链接库。。

    WSADATA wsaData;
    WORD wVersionRequested = MAKEWORD(2, 2);
    if (WSAStartup(wVersionRequested, &wsaData) != 0)
    {
    	std::cout << "加载winsock.dll失败!" << std::endl;
    	return 0;
    }
    
  6. socket:创建套接字,指定地址族(AF_INET)、套接字类型(SOCK_STREAM)和协议(0表示根据地址族和套接字类型自动选择)。

    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    
  7. bind:将套接字绑定到指定的IP地址和端口。第一个参数为socket,第二个参数是一个结构指针,它包含了端口和IP地址信息,第三个参数表示缓冲区长度。

    sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &serverAddress.sin_addr);
    bind(serverSocket, reinterpret_cast<SOCKADDR*>(&serverAddress), sizeof(serverAddress));
    
  8. inet_pton()函数用于将点分十进制的IP地址转换为网络字节序的二进制形式。并将结果存储在serverAddress.sin_addr中。

    注意:inet_pton()函数是一个标准的C函数,位于头文件arpa/inet.h中。它返回一个整数值,指示转换的结果是否成功。如果返回值为1,表示转换成功;如果返回值为0,表示输入的IP地址无效;如果返回值为-1,表示发生了错误,可以使用errno变量获取具体的错误信息。

  9. htons:将一个16位无符号短整型数据由主机排列方式转化为网络排列方式,htonl函数的作用相反。

    serverAddress.sin_port = htons(PORT);
    
  10. listen:开始监听客户端连接请求。第一个参数为socket,第二个参数为等待连接最大队列的长度。将socket设置为监听模式,服务端的socket特有。必须将服务端的socket设置为监听模式才能和服务端建立连接。

    listen(serverSocket, 0);
    
  11. accept:服务端socket接受客户端的连接请求,返回一个新的套接字以用于与客户端通信。第一个参数为socket,第二个参数为包含客户端端口IP信息的sockaddr_in结构指针,第三个参数为接收参数addr的长度。

sockaddr_in clientAddress;
int clientAddressSize = sizeof(clientAddress);
SOCKET clientSocket = accept(serverSocket, reinterpret_cast<SOCKADDR*>(&clientAddress), &clientAddressSize);
  1. std::thread:使用C++11的std::thread库创建新的线程,将HandleClientCommunication函数作为线程的入口点,并传递客户端套接字作为参数。

  2. recv接收数据,第一个参数为socket,第二个参数为接收数据缓冲区,第三个参数为缓冲区的长度,第四个参数为函数的调用方式。

    int receivedBytes = recv(clientSocket, buffer, sizeof(buffer), 0);
    
  3. send发送数据,里面的参数基本和recv()一样。

    int size = send(clientSocket, message.c_str(), static_cast<int>(message.length()), 0);
    

以上是对服务端代码的详细分析。代码实现了一个简单的TCP服务器,能够与多个客户端进行通信。代码仍然有改进的空间,例如可以处理更多的错误情况,添加更多的日志输出,以及更完善的内存管理等。


二、客户端client实现

1. client代码

#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <string>

#pragma comment(lib, "ws2_32.lib")
#define PORT 65432

void Cleanup(SOCKET socket)
{
	closesocket(socket);
	WSACleanup();
}

int main()
{
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		std::cout << "加载winsock.dll失败!" << std::endl;
		return 0;
	}

	SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (clientSocket == INVALID_SOCKET)
	{
		std::cout << "创建套接字失败!错误代码:" << WSAGetLastError() << std::endl;
		Cleanup(clientSocket);
		return 0;
	}

	sockaddr_in serverAddress;
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_port = htons(PORT);
	inet_pton(AF_INET, "127.0.0.1", &serverAddress.sin_addr);

	if (connect(clientSocket, reinterpret_cast<SOCKADDR*>(&serverAddress), sizeof(serverAddress)) == SOCKET_ERROR)
	{
		std::cout << "连接失败!错误代码:" << WSAGetLastError() << std::endl;
		Cleanup(clientSocket);
		return 0;
	}

	while (true)
	{
		std::string receivedMessage;
		char buffer[1000];
		int size = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
		if (size <= 0)
		{
			if (size == 0)
				std::cout << "连接已关闭" << std::endl;
			else
				std::cout << "接收信息失败!错误代码:" << WSAGetLastError() << std::endl;
			break;
		}
		buffer[size] = '\0';
		receivedMessage = buffer;
		if (receivedMessage == "end")
		{
			std::cout << "服务器端已关闭连接!" << std::endl;
			break;
		}
		else
		{
			std::cout << "收到服务器消息:" << receivedMessage << std::endl;
		}

		std::string sendMessage;
		std::cout << "请输入要发送给服务器的消息:" << std::endl;
		std::getline(std::cin, sendMessage);

		if (sendMessage == "end")
		{
			std::cout << "关闭连接!" << std::endl;
			break;
		}

		int sentBytes = send(clientSocket, sendMessage.c_str(), static_cast<int>(sendMessage.length()), 0);
		if (sentBytes == SOCKET_ERROR || sentBytes == 0)
		{
			std::cout << "[发送信息失败] 错误代码:" << WSAGetLastError() << std::endl;
			break;
		}
		else
		{
			std::cout << "       [信息发送成功]" << std::endl;
		}
	}

	Cleanup(clientSocket);
	return 0;
}

2. 代码详解

上述代码是一个使用Winsock库实现的简单的TCP客户端,它连接到指定的服务器并与之进行通信。下面对代码进行详细分析:

  1. Cleanup函数:与之前的代码相同,用于关闭套接字并清理WSA的资源。

  2. main函数:程序的入口函数。它首先初始化Winsock库,然后创建一个套接字并尝试连接到服务器。接下来,进入一个无限循环,循环中首先接收服务器发送的消息,然后等待用户输入要发送给服务器的消息。如果接收到的消息是"end",表示服务器要求关闭连接,循环会退出。如果用户输入的消息是"end",表示用户主动要求关闭连接,循环也会退出。

  3. WSAStartup:与之前的代码相同,初始化Winsock库。

  4. socket:与之前的代码相同,创建套接字。

  5. connect:客户端socket发送连接请求的函数,尝试连接到指定的服务器地址和端口。第一个参数是客户端的socket,第二个参数是一个结构体指针,里面包括连接主机的地址和ip,第三个参数为缓冲区的长度。

    connect(clientSocket, reinterpret_cast<SOCKADDR*>(&serverAddress), sizeof(serverAddress));
    
  6. recv:接收服务器发送的消息,将其存储在buffer中,然后通过对buffer进行处理得到receivedMessage

  7. send:将用户输入的消息发送给服务器。

以上是客户端代码的详细分析。代码实现了一个简单的TCP客户端,能够与服务器进行通信。代码仍然有改进的空间,例如可以处理更多的错误情况,添加更多的日志输出,以及更完善的输入验证等。

三、运行效果图

tcp client/server c++代码,C++,c++,tcp/ip,开发语言,网络

四、总结

  • 服务端有一个ServerSocket,初始化以后(设置IP和端口,绑定监听等),使用accept()方法等待客户端连接,这个方法是阻塞的。一旦连接成功,会返回一个新的Socket,使用这个Socket就可以接收数据和发送数据了。

  • 客户端自始始终都只有一个Socket,这个Socket初始化以后,使用connect()方法和服务器进行连接,连接成功后,这个Socket就可以进行通信了。


如果这篇文章对你有所帮助,渴望获得你的一个点赞!

tcp client/server c++代码,C++,c++,tcp/ip,开发语言,网络文章来源地址https://www.toymoban.com/news/detail-772031.html

到了这里,关于【C++】TCP通信服务端与客户端代码实现及详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 服务端和客户端通信-TCP(含完整源代码)

    目录 简单TCP通信实验 分析 1、套接字类型 2、socket编程步骤 3、socket编程实现具体思路 实验结果截图 程序代码 实验设备:     目标系统:windows 软件工具:vs2022/VC6/dev 实验要求: 完成TCP服务端和客户端的程序编写; 实现简单字符串的收发功能。 需附上代码及运行结果截图

    2024年02月07日
    浏览(76)
  • C++网络编程 TCP套接字基础知识,利用TCP套接字实现客户端-服务端通信

    流式套接字编程针对TCP协议通信,即是面向对象的通信,分为服务端和客户端两部分。 1)加载套接字库( 使用函数WSAStartup() ),创建套接字( 使用socket() ) 2)绑定套接字到一个IP地址和一个端口上( 使用函数bind() ) 3)将套接字设置为监听模式等待连接请求( 使用函数

    2024年02月03日
    浏览(60)
  • C++实现一个简单的客户端与服务端的通信(笔记附代码)

    目录 前言 一、Socket的客户端与服务端的通讯原理 二、各接口介绍 1.WSAStartup:异步启动套接字命令 2.Socket创建套接字 3.bind:绑定套接字 4.listen:监听 5.accept:接受连接请求 6. connet:发送连接请求  7.send:发送数据 8.recv:接收数据函数  9.closesocket, WSACleanup:释放socket 三、代码块的

    2024年02月06日
    浏览(52)
  • 网络编程3——TCP Socket实现的客户端服务器通信完整代码(详细注释帮你快速理解)

    本人是一个刚刚上路的IT新兵,菜鸟!分享一点自己的见解,如果有错误的地方欢迎各位大佬莅临指导,如果这篇文章可以帮助到你,劳请大家点赞转发支持一下! 今天分享的内容是TCP流套接字实现的客户端与服务器的通信,一定要理解 DatagramSocket,DatagramPacket 这两个类的作用以及方法

    2024年02月12日
    浏览(63)
  • Java【网络编程2】使用 TCP 的 Socket API 实现客户端服务器通信(保姆级教学, 附代码)

    📕各位读者好, 我是小陈, 这是我的个人主页 📗小陈还在持续努力学习编程, 努力通过博客输出所学知识 📘如果本篇对你有帮助, 烦请点赞关注支持一波, 感激不尽 📙 希望我的专栏能够帮助到你: JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统

    2024年02月05日
    浏览(65)
  • tcp通信,客户端服务端

    //TCP通信的流程 //服务器端(被动接受连接的角色) 1.创建一个用于监听的套接字         -监听:监听有客户端的连接         -套接字:这个套接字其实就是一个文件描述符 2.将这个监听文件描述符和本地的IP和端口绑定(IP和端口就是服务器的地址信息)         -客户端

    2024年02月09日
    浏览(36)
  • TCP实现服务器和客户端通信

    目录 TCP介绍 代码实现 server(服务器端) 代码分析 client(客户端) 代码分析 结果展示 TCP (Transmission Control Protocol) 是一种面向连接的协议,用于在计算机网络中传输数据。TCP 可以确保数据的可靠传输,即使在网络环境不稳定的情况下也能够保证数据的完整性和顺序。以下是

    2024年02月15日
    浏览(62)
  • QTday05(TCP的服务端客户端通信)

    pro文件需要导入  network 头文件: widget.cpp ui: 头文件 widget.cpp ui: 运行结果:客户端连接之后可以成功发送信息 今日思维导图: 代码: page2.h: widget.h: main.cpp: page2.cpp: widget.cpp: page2.ui: widget.ui: 运行结果:

    2024年02月07日
    浏览(39)
  • 简易TCP客户端和服务器端通信

    #includeiostream #include winsock2.h   #include ws2tcpip.h   #includestdlib.h using namespace std; #define  BUF_SIZE  1024 int main() {     cout \\\"客户端\\\" endl;     //设置Winsock版本,     WSADATA   wsaData;     if (WSAStartup(MAKEWORD(2, 2), wsaData) != 0)     {         cout \\\"error\\\" endl;         exit(1);     }     //创建通

    2024年04月29日
    浏览(49)
  • TCP通信实现客户端向服务器发送图片

    TCP通信: 1. TCP 协议通信交互流程: 具体的流程如下: (1)服务器根据地址类型(ipv4、ipv6)、socket 类型、协议创建 socket. (2)服务器为 socket 绑定 ip 地址和端口号。 (3)服务器 socket 监听端口号的请求,随时准备接受来自客户端的连接,此时服务器的 socket 处于关闭状态

    2024年02月13日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包