From 06095ace67ceeeb1a53faea3565bccdee5fd31b2 Mon Sep 17 00:00:00 2001
From: hjz <513795900@qq.com>
Date: 星期三, 04 十二月 2024 11:52:18 +0800
Subject: [PATCH] Merge branch 'master' of ssh://115.28.86.8:29418/~admin/脸谱AI_0817_1202

---
 GroupB_马喜龙/Public/脸谱-设计说明书-B组.docx                                                     |    0 
 GroupB_马喜龙/Public/脸谱-项目计划表-B组.xlsx                                                     |    0 
 GroupB_马喜龙/Server/马喜龙/code/face_painting_socket_server/ServerSocket.h                  |   70 ++++++++
 GroupB_马喜龙/Server/马喜龙/code/face_painting_socket_server/ThreadPool.hpp                  |  147 ++++++++++++++++++
 GroupB_马喜龙/Public/脸谱-风险控制表-B组.docx                                                     |    0 
 GroupB_马喜龙/Server/马喜龙/code/face_painting_socket_server/main.cpp                        |   39 ++++
 GroupB_马喜龙/Public/脸谱-编码规范-B组.docx                                                      |    0 
 GroupB_马喜龙/Public/脸谱-项目需求分析文档-B组.docx                                                  |    0 
 GroupB_马喜龙/Server/马喜龙/code/face_painting_socket_server/ServerSocket.cpp                |  187 +++++++++++++++++++++++
 GroupB_马喜龙/Server/马喜龙/code/face_painting_socket_server/face_painting_socket_server.sln |   28 +++
 10 files changed, 471 insertions(+), 0 deletions(-)

diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\347\274\226\347\240\201\350\247\204\350\214\203-B\347\273\204.docx" "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\347\274\226\347\240\201\350\247\204\350\214\203-B\347\273\204.docx"
new file mode 100644
index 0000000..674f38b
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\347\274\226\347\240\201\350\247\204\350\214\203-B\347\273\204.docx"
Binary files differ
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\350\256\276\350\256\241\350\257\264\346\230\216\344\271\246-B\347\273\204.docx" "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\350\256\276\350\256\241\350\257\264\346\230\216\344\271\246-B\347\273\204.docx"
new file mode 100644
index 0000000..f3b09a3
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\350\256\276\350\256\241\350\257\264\346\230\216\344\271\246-B\347\273\204.docx"
Binary files differ
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\241\271\347\233\256\350\256\241\345\210\222\350\241\250-B\347\273\204.xlsx" "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\241\271\347\233\256\350\256\241\345\210\222\350\241\250-B\347\273\204.xlsx"
new file mode 100644
index 0000000..906aeda
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\241\271\347\233\256\350\256\241\345\210\222\350\241\250-B\347\273\204.xlsx"
Binary files differ
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\241\271\347\233\256\351\234\200\346\261\202\345\210\206\346\236\220\346\226\207\346\241\243-B\347\273\204.docx" "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\241\271\347\233\256\351\234\200\346\261\202\345\210\206\346\236\220\346\226\207\346\241\243-B\347\273\204.docx"
new file mode 100644
index 0000000..40110a3
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\241\271\347\233\256\351\234\200\346\261\202\345\210\206\346\236\220\346\226\207\346\241\243-B\347\273\204.docx"
Binary files differ
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\243\216\351\231\251\346\216\247\345\210\266\350\241\250-B\347\273\204.docx" "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\243\216\351\231\251\346\216\247\345\210\266\350\241\250-B\347\273\204.docx"
new file mode 100644
index 0000000..5732068
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Public/\350\204\270\350\260\261-\351\243\216\351\231\251\346\216\247\345\210\266\350\241\250-B\347\273\204.docx"
Binary files differ
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ServerSocket.cpp" "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ServerSocket.cpp"
new file mode 100644
index 0000000..46ef42a
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ServerSocket.cpp"
@@ -0,0 +1,187 @@
+#include "ServerSocket.h"
+
+ServerSocket::ServerSocket()
+{
+	if (initSocket()) cout << "Socket init successed!" << endl;
+	else cout << "Socket init failed!" << endl;
+}
+
+ServerSocket::~ServerSocket()
+{
+	closesocket(m_server);
+	WSACleanup();
+}
+
+bool ServerSocket::initSocket()
+{
+	WSAData wsa;
+	int val = WSAStartup(MAKEWORD(2, 2), &wsa);
+	if (val != 0)
+	{
+		cout << "WSAStartup failed!"<<endl;
+	}
+
+	m_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	SOCKADDR_IN addr;
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(PORT); //处理大小端
+	addr.sin_addr.S_un.S_addr = 0;
+	int ret_bind = bind(m_server, (sockaddr*)&addr, sizeof(addr));
+	if (ret_bind) {
+		cout << "bind fail:" << WSAGetLastError() << endl;
+		return false;
+	}
+	int ret_listen = listen(m_server, 5);
+	if (ret_listen) {
+		cout << "listen fail:" << WSAGetLastError() << endl;
+		return false;
+	}
+	thread accept_thread(&ServerSocket::acceptThread, this);
+	accept_thread.detach(); // 防止异常结束
+
+	thread mMap_Delete(&ServerSocket::mMapDelete, this);
+	mMap_Delete.detach();
+
+	return true;
+}
+
+void ServerSocket::acceptThread()
+{
+	while (true) {
+		SOCKET client;
+		SOCKADDR_IN addr;
+		int len = sizeof(addr);
+		cout << "waiting for connect..." << endl;
+		client = accept(m_server, (sockaddr*)&addr, &len);
+		cout << "client:" << client << endl;
+		if (client == SOCKET_ERROR) {
+			cout << "socket 异常" << WSAGetLastError() << endl;
+			break;
+		}
+		else if (client == 0) {
+			cout << "socket 已关闭:" << WSAGetLastError() << endl;
+			break;
+		}
+		// 正常 连上了
+		// 启动长连接线程,进行交互
+		mMapInsert(client);
+
+		thread heart_check(&ServerSocket::heartBeatThread, this, client);
+		heart_check.detach();
+
+		thread recv_send(&ServerSocket::recvAndSendThread, this, client);
+		recv_send.detach();
+
+	}
+}
+
+void ServerSocket::recvAndSendThread(SOCKET client)
+{
+	while (true)
+	{
+		// 解决粘包问题,顺带也解决了拆包问题
+		char* buffer = new char[sizeof(Head)];
+		int len_recv = recv(client, buffer, sizeof(Head), 0);
+		int head_rest = sizeof(Head) - len_recv; // 剩余长度
+		while (head_rest > 0) {  // 保证数据头能够全收到
+			len_recv = recv(client, buffer + (sizeof(Head) - head_rest), head_rest, 0);
+			head_rest -= len_recv;
+		}
+		Head* head = (Head*)buffer; // 转成对应结构体,再取出封包总长度
+		int len_total = head->len;
+		//int len_total = *(int*)(buffer + 4); // 还可以直接转为Head*,指出长度
+		char* buffer_all = new char[len_total];
+		memcpy(buffer_all, buffer, sizeof(Head)); // 拷贝数据头进总的缓冲区
+
+		int len_rest = len_total - sizeof(Head);
+		while (len_rest > 0) {  // 保证数据体能够全部收到
+			len_recv = recv(client, buffer_all + (len_total - len_rest), len_rest, 0);
+			len_rest -= len_recv;
+		}
+
+		// 正常
+		//m_clientMap[client] = HEART_CHECK_TIMES; // 重置心跳阈值
+
+		int type = *(int*)buffer;
+		if (type == 110) {
+			/*TestSturct2* ts2 = (TestSturct2*)buffer_all; // 转换时,使用总的buffer_all
+			if (ts2) {
+				ts2->a = (char*)ts2 + sizeof(TestSturct2);
+				ts2->b = ts2->a + strlen(ts2->a) + 1;
+				cout << ts2->len;
+				cout << "内容1: " << ts2->a << endl;
+				cout << "内容2: " << ts2->b << endl;
+			}*/
+		}
+		/*else if (type == LOGIN_REQ) {
+			// 登录请求
+			LoginReq* req = (LoginReq*)buffer_all; // 转换时,使用总的buffer_all
+			cout << "用户信息:" << req->user_name << " " << req->password << endl;
+			Login login;
+			login.business(req, client); // 调用业务处理API
+		}*/
+		if (type == HEART_CHECK_REQ) {
+			// 收到心跳请求包,回响应包
+			HeartCheckRes res;
+			send(client, (char*)&res, res.len, 0);
+			cout << "已回复包!" << endl;
+		}
+
+		// 原封不动的回包
+		//send(client, buffer_all, len_total, 0);
+
+		// 用完了,记得释放动态开辟的内存
+		if (buffer)
+		{
+			delete[] buffer;
+			buffer = nullptr; // 防止指针悬空,而产生悬空指针
+		}
+		if (buffer_all) {
+			delete[] buffer_all;
+			buffer_all = nullptr;
+		}
+
+	}
+}
+
+void ServerSocket::heartBeatThread(SOCKET client)
+{
+	while (true)
+	{
+		Sleep(HEARTBEAT_INTERVAL * 1000);
+		mutex heartLock;
+		lock_guard<std::mutex> lock(heartLock);
+		--m_clientMap[client];
+
+	}
+}
+
+void ServerSocket::mMapInsert(SOCKET client)
+{
+	lock_guard<mutex> lg(m_mutex);
+	m_clientMap.insert(make_pair(client, HEART_CHECK_TIMES));
+	cout << "插入成功:times = " << m_clientMap[client] << endl;
+}
+
+void ServerSocket::mMapUpdate(SOCKET client)
+{
+	lock_guard<mutex> lg(m_mutex);
+	m_clientMap.insert(make_pair(client, HEART_CHECK_TIMES));
+}
+
+void ServerSocket::mMapDelete()
+{
+	while (true)
+	{
+		Sleep(HEARTBEAT_INTERVAL * 1000);
+		lock_guard<std::mutex> lock(m_mutex);
+		for (auto& client_socket : m_clientMap) {
+			cout << client_socket.second << endl;
+			if (client_socket.second <= 0) {
+				closesocket(client_socket.first);
+				m_clientMap.erase(client_socket.first);
+				cout << "删除连接成功" << endl;
+			}
+		}
+	}
+}
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ServerSocket.h" "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ServerSocket.h"
new file mode 100644
index 0000000..e818f09
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ServerSocket.h"
@@ -0,0 +1,70 @@
+#pragma once
+#include <WinSock2.h>
+#include <iostream>
+#include <map>
+#include <thread>
+#include <mutex>
+#include "ThreadPool.hpp"
+#pragma comment(lib,"ws2_32.lib")
+
+#define PORT 9527
+#define HEART_CHECK_REQ 101
+#define HEART_CHECK_RES 102
+#define HEART_CHECK_TIMES 6
+#define HEARTBEAT_INTERVAL 2
+
+
+
+using namespace std;
+
+struct Head
+{
+	int type; // 区分不同功能类型
+	int len;  // 表示整个封包的长度,是为了后面处理粘包问题的
+};
+
+// 间隔:5秒,阈值为6,递减从6开始,到0或小于0 断开/重连
+// 心跳请求包
+struct HeartCheckReq  
+{
+	int type;
+	int len;
+	HeartCheckReq()
+	{
+		type = 101;
+		len = sizeof(HeartCheckReq);
+	}
+};
+
+// 心跳响应包
+struct HeartCheckRes  
+{
+	int type;
+	int len;
+	HeartCheckRes()
+	{
+		type = 102;
+		len = sizeof(HeartCheckRes);
+	}
+};
+
+class ServerSocket
+{
+public:
+	ServerSocket();
+	virtual ~ServerSocket();
+
+	bool initSocket();
+	void acceptThread();
+	void recvAndSendThread(SOCKET client);
+	void heartBeatThread(SOCKET client);
+
+	void mMapInsert(SOCKET client);
+	void mMapUpdate(SOCKET client);
+	void mMapDelete();
+private:
+	SOCKET m_server;
+	map<SOCKET, int> m_clientMap;
+	mutex m_mutex;
+};
+
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ThreadPool.hpp" "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ThreadPool.hpp"
new file mode 100644
index 0000000..a2986bc
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/ThreadPool.hpp"
@@ -0,0 +1,147 @@
+#pragma once
+#include <iostream>
+#include <mutex>
+#include <atomic>
+#include <condition_variable>
+#include <queue>
+#include <string>
+
+using namespace std;
+
+template<typename Task, const size_t DEFAULT_THREAD_NUM, const size_t MAX_THREAD_NUM>
+class ThreadPool
+{
+public:
+	ThreadPool() = delete;
+	ThreadPool(const ThreadPool&) = delete;
+	ThreadPool& operator=(const ThreadPool&) = delete;
+	ThreadPool(ThreadPool&&) = delete;
+	ThreadPool& operator=(ThreadPool&&) = delete;
+
+	explicit ThreadPool(uint32_t timeout) :m_timeout(timeout), m_needRun(true)
+	{
+		for (int i = 0; i < DEFAULT_THREAD_NUM; i++)
+		{
+			thread([this] { RunTask(); }).detach();
+		}
+	}
+	~ThreadPool() {
+		m_needRun = false;
+		while (m_runningThreadNum > 0)
+		{
+			m_needRunCondition.notify_all();
+		}
+
+	}
+	void Push(Task& task) {
+		PushTask(task);
+		if (m_runningThreadNum < MAX_THREAD_NUM && m_idleThreadNum == 0)
+		{
+			thread([this] { RunTask(); }).detach();
+		}
+		m_needRunCondition.notify_all();
+	}
+private:
+	bool IsQueueEmpty() {
+		lock_guard<mutex> lg(m_mutex);
+		return m_taskQueue.empty();
+	}
+	bool GetTask(Task& task) {
+		lock_guard<mutex> lg(m_mutex);
+		if (m_taskQueue.empty())
+		{
+			return false;
+		}
+		task = m_taskQueue.top();
+		m_taskQueue.pop();
+		return true;
+	}
+	class NumWrapper
+	{
+	public:
+		NumWrapper() = delete;
+		NumWrapper(atomic<uint32_t>& num) :m_num(num) { m_num++; }
+		~NumWrapper() { m_num--; }
+
+	private:
+		atomic<uint32_t>& m_num;
+	};
+
+	void Sleep() {
+		mutex needRunMutex;
+		unique_lock<mutex> lock(needRunMutex);
+
+		NumWrapper idleWraper(m_idleThreadNum);
+		(void)idleWraper;
+
+		m_needRunCondition.wait_for(lock, std::chrono::seconds(m_timeout),
+			[this] { return !m_needRun || !IsQueueEmpty(); });
+	}
+	void PushTask(const Task& task) {
+		lock_guard<mutex> lg(m_mutex);
+		m_taskQueue.push(task);
+	}
+	void RunTask() {
+		NumWrapper runWraper(m_runningThreadNum);
+		(void)runWraper;
+
+		while (m_needRun)
+		{
+			Task task;
+			if (GetTask(task))
+			{
+				task.Execute();
+				continue;
+			}
+			Sleep();
+
+			if (!m_needRun)
+			{
+				return;
+			}
+			if (GetTask(task))
+			{
+				task.Execute();
+				continue;
+			}
+			if (m_runningThreadNum > DEFAULT_THREAD_NUM)
+			{
+				return;
+			}
+		}
+	}
+
+private:
+	atomic<uint32_t> m_idleThreadNum;
+	atomic<uint32_t> m_runningThreadNum;
+	atomic_bool m_needRun;
+
+	mutex m_mutex;
+	condition_variable m_needRunCondition;
+	uint32_t m_timeout;
+	priority_queue<Task> m_taskQueue;
+};
+
+class Task
+{
+public:
+	Task() :m_priority(0) {};
+	explicit Task(string context) :m_priority(0) {
+		m_context = context;
+	}
+
+	bool operator<(const Task& t) const {
+		return m_priority < t.m_priority;
+	}
+
+	void Execute() {
+		lock_guard<mutex> lg(m_mutex);
+		cout << "Task is executed,name is" << m_context << endl;
+	}
+
+public:
+	uint32_t m_priority;
+private:
+	string m_context;
+	static mutex m_mutex;
+};
\ No newline at end of file
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/face_painting_socket_server.sln" "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/face_painting_socket_server.sln"
new file mode 100644
index 0000000..079f4ad
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/face_painting_socket_server.sln"
@@ -0,0 +1,28 @@
+锘�
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35521.163 d17.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "face_painting_socket_server", "face_painting_socket_server.vcxproj", "{8F47EF20-7DBA-475C-ABA7-C468E46049F2}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{8F47EF20-7DBA-475C-ABA7-C468E46049F2}.Debug|x64.ActiveCfg = Debug|x64
+		{8F47EF20-7DBA-475C-ABA7-C468E46049F2}.Debug|x64.Build.0 = Debug|x64
+		{8F47EF20-7DBA-475C-ABA7-C468E46049F2}.Debug|x86.ActiveCfg = Debug|Win32
+		{8F47EF20-7DBA-475C-ABA7-C468E46049F2}.Debug|x86.Build.0 = Debug|Win32
+		{8F47EF20-7DBA-475C-ABA7-C468E46049F2}.Release|x64.ActiveCfg = Release|x64
+		{8F47EF20-7DBA-475C-ABA7-C468E46049F2}.Release|x64.Build.0 = Release|x64
+		{8F47EF20-7DBA-475C-ABA7-C468E46049F2}.Release|x86.ActiveCfg = Release|Win32
+		{8F47EF20-7DBA-475C-ABA7-C468E46049F2}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git "a/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/main.cpp" "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/main.cpp"
new file mode 100644
index 0000000..7f17ae5
--- /dev/null
+++ "b/GroupB_\351\251\254\345\226\234\351\276\231/Server/\351\251\254\345\226\234\351\276\231/code/face_painting_socket_server/main.cpp"
@@ -0,0 +1,39 @@
+#include <iostream>
+#include "ServerSocket.h"
+#include "ThreadPool.hpp"
+using namespace std;
+
+#define DEFAULT_THREAD_NUM 3
+#define MAX_THREAD_NUM 6
+#define TIME_OUT 500
+mutex Task::m_mutex;
+
+int main() {
+	ServerSocket server1;
+	string cmd;
+	while (cin>>cmd)
+	{
+		if (cmd == "quit") {
+			break;
+		}
+	}
+
+	/*ThreadPool<Task, DEFAULT_THREAD_NUM, MAX_THREAD_NUM> threadPool_(TIME_OUT);
+	Task task1("name_1");
+	Task task2("name_2");
+	Task task3("name_3");
+	Task task4("name_4");
+
+	task4.m_priority = 4;
+	task3.m_priority = 8;
+	task2.m_priority = 2;
+	task1.m_priority = 5;
+
+	threadPool_.Push(task1);
+	threadPool_.Push(task2);
+	threadPool_.Push(task3);
+	threadPool_.Push(task4);*/
+
+	system("pause");
+	return 0;
+}
\ No newline at end of file

--
Gitblit v1.8.0