C++使用多线程创建TCP服务端及发送指定长度和接收报文

通过清心醉

C++使用多线程创建TCP服务端及发送指定长度和接收报文

由于使用WIN,直接使用CreateThread方式。线程的释放,自行处理。(虽然代码中止会return 0)

客户端代码:

#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <random>
using  namespace std;
#pragma comment(lib, "ws2_32.lib")

//获取随机长度的字符串
string GetLengStr(int length) {

	string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
	std::string result;
	std::random_device rd;
	std::mt19937 gen(rd());
	std::uniform_int_distribution<> dis(0, charset.size() - 1);

	for (int i = 0; i < length; ++i) {
		result += charset[dis(gen)];
	}

	return result;
}
int  main()
{
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		cout << "加载winsock.dll失败!" << endl;
		return 0;
	}
	//创建套接字
	SOCKET  sock_client;
	if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
	{
		cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
		WSACleanup();
		return 0;
	}
	//连接服务器
	sockaddr_in   addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(9999); //端口
	inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
	int len = sizeof(sockaddr_in);
	if (connect(sock_client, (SOCKADDR*)&addr, len) == SOCKET_ERROR) {
		cout << "连接失败!错误代码:" << WSAGetLastError() << endl;
		return 0;
	}
	cout << "开始和服务器通讯" << endl;
	int leng = 10;
	string str;
	while (1)
	{
		if (leng >= 32) { //别一直循环
			break;//跳出,可以自己做重连动作
		}
		leng++;
		str = GetLengStr(leng); //获取随机长度的字符串
		char setData[1024]; //定义一个最大1024的变量
		int len = str.copy(setData, 1024); //获取实际的有效长度
		int ret = send(sock_client, setData, len, 0);
		if (ret == SOCKET_ERROR || ret == 0)
		{
			cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
			break;
		}
		else {
			cout << "信息发送成功!发送的内容:" << setData << "长度"<< sizeof(len)<<endl;
			Sleep(2000);
		}
		char getData[1024];
		int ret1 = recv(sock_client, getData, sizeof(getData), 0);
		if (ret1 == SOCKET_ERROR || ret1 == 0)
		{
			break; //跳出,可以自己做重连动作
		}
		else {
			cout << "获取内容:" << getData << endl;
		}
		
	}
	closesocket(sock_client);
	WSACleanup();
	return 0;
}

MFC版:

#include <winsock2.h>
#include <WS2tcpip.h>
//MFC里只需要包含以上2文件即可
DWORD WINAPI TcpServerRun(LPVOID lpParameter) {
	SOCKET sock = (SOCKET)lpParameter;
	//先设置一个接收报文的长度
	string str;
	CString cstr;
	CString length;
	while (true) {
		//4个字节的,用来统计获取的包数量,然后第二次才是执行内容获取
		char bufferdata[1024];
		int ret = recv(sock, bufferdata, sizeof(bufferdata), 0);
		if (ret == SOCKET_ERROR || ret == 0)
		{
			closesocket(sock);    return 0;
		char bufferdata[1024];
		int ret = recv(sock, bufferdata, sizeof(bufferdata), 0);
		if (ret == SOCKET_ERROR || ret == 0)
		{
			closesocket(sock);    return 0;
		}
		str = bufferdata; //先把获取的给string
		cstr = L"收到内容:";
		cstr += str.c_str();
		cstr += "长度:";
		length.Format(TEXT("%d"), str.size());
		cstr += length;
		char setData[32] = "发回给客户端的动作";
		int ret1 = send(sock, setData, sizeof(setData), 0);
		if (ret1 == SOCKET_ERROR || ret1 == 0) {
			closesocket(sock);    return 0;
		}
	}
	return 0;
}
//创建一个TCP服务端
DWORD WINAPI TcpServer(LPVOID lpParameter) {
	C控制程序Dlg* pThis = (C控制程序Dlg*)lpParameter;
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		pThis->MessageBox(L"加载winsock.dll失败!");
		return 0;
	}
	//创建套接字
	SOCKET  sock_server;
	if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
	{
		pThis->MessageBox(L"创建套接字失败!!");
		WSACleanup();
		return 0;
	}
	//绑定端口和Ip
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(9999);
	inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
	if (SOCKET_ERROR == bind(sock_server, (SOCKADDR*)&addr, sizeof(sockaddr_in)))
	{
		pThis->MessageBox(L"地址绑定失败!");
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	//将套接字设为监听状态
	listen(sock_server, 0);
	//主线程循环接收客户端的连接
	while (1)
	{
		sockaddr_in addrClient;
		int len = sizeof(sockaddr_in);
		SOCKET sock = accept(sock_server, (SOCKADDR*)&addrClient, &len);
		if (sock != INVALID_SOCKET)
		{
			//pThis->MessageBox(L"检测到TCP客户端连接");
			CreateThread(0, 0, TcpServerRun,(LPVOID)sock, 0, 0); //创建一个线程,传入(LPVOID)sock资源
		}
	}
	return 0;
}

这里自己用一个button事件来触发调用,这里是线程里创建线程。否则主进程会卡住挂起。
void C我的TCP服务端Dlg::OnBnClickedButton1(){
CreateThread(0, 0, TcpServer, (LPVOID)this, 0, 0); //创建TCP服务端线程。
}

再来一个cmd版本的,注意,MFC框架里,内容的长度无需特别操作。注意,编码等问题,包括获取的,自行处理了。

#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <random>
#include <string>
#include <Windows.h>
using  namespace std;
#pragma comment(lib, "ws2_32.lib")

DWORD WINAPI TcpServerRun(LPVOID lpParameter) {
	SOCKET sock = (SOCKET)lpParameter;
	//先设置一个接收报文的长度
	string str;
	while (true) {
		//4个字节的,用来统计获取的包数量,然后第二次才是执行内容获取
		char msgbuffe[1024];
		int ret = recv(sock, msgbuffe, sizeof(msgbuffe), 0);
		if (ret == SOCKET_ERROR || ret == 0)
		{
			break; //跳出并且关闭
		}
		str = msgbuffe;
		str.copy(msgbuffe, 1024); //获取实际的有效长度
		cout << msgbuffe << endl;
		char setData[32] = "发回给客户端的动作";
		int ret1 = send(sock, setData, sizeof(setData), 0);
		if (ret1 == SOCKET_ERROR || ret1 == 0) {
			break; //跳出并且关闭
		}
	}
	closesocket(sock); //记得释放socket
	WSACleanup();
	return 0;
}
//创建一个TCP服务端
int main() {
	system("chcp 65001");
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		cout << "加载winsock.dll失败!" << endl;
		return 0;
	}
	//创建套接字
	SOCKET  sock_server;
	if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
	{
		cout << "创建套接字失败!!" << endl;
		WSACleanup();
		return 0;
	}
	//绑定端口和Ip
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(9999);
	inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
	if (SOCKET_ERROR == bind(sock_server, (SOCKADDR*)&addr, sizeof(sockaddr_in)))
	{
		cout << "地址绑定失败!" << endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	//将套接字设为监听状态
	listen(sock_server, 0);
	while (1)
	{
		sockaddr_in addrClient;
		int len = sizeof(sockaddr_in);
		SOCKET sock = accept(sock_server, (SOCKADDR*)&addrClient, &len);
		if (sock != INVALID_SOCKET)
		{
			CreateThread(0, 0, TcpServerRun, (LPVOID)sock, 0, 0); //创建一个线程,传入(LPVOID)sock资源
		}
	}
	return 0;
}

关于作者

清心醉 administrator

发表评论

请输入验证码: