就是有这么一个需求,把程序生成的数据文件内容加密,并且有一个解密程序,解密程序要把加密的数据上传到服务器,并且保存在服务器数据库和服务器磁盘里,在得到服务器验证之后要把数据在本地解密。
加解密用的是AES算法。之前用过gRPC实现客户端和服务器的通信,但是加密需要用C++,C++在Windows上写gRPC客户端不太好搞,于是就想到了HTTP协议,在网上找了个开源的http webserver叫mongoose,用它做客户端,服务器用的是python的socket,python比较好操作数据库,但是使用解密算法和计算参数需要使用C++的DLL的导出函数,这个用的是ctypes来实现的。实现了用C++客户端发送get请求,只发送很少的加密数据到服务器,服务器把数据存到数据库并且返回验证参数,客户端在本地解密的功能。后来需要发送很长的数据,但是get请求有长度限制,就要用post请求了,但是我又不会post,找了一下最终决定客户端也用C++的socket了,很方便想发什么发什么,其实感觉这个需求的话一开始就应该直接用socket。socket跑出效果还是非常快的,这里把部分源码贴出来,做个记录。
服务端:
#这是python调用C++DLL的函数的方法
pDll = ctypes.WinDLL("C:/Users/Administrator/aurora111.dll")
strSrc = bytes(IMEI, encoding='utf-8')
#如果是返回字符串指针,那么就必须像下面这样修改返回类型
pDll.DecryptionAES.restype = ctypes.c_uint64
pointer = pDll.DecryptionAES(strSrc)
need_str = str(ctypes.string_at(pointer), encoding='utf-8', errors='ignore')
#python创建socket,监听端口,有用户连上就调用处理的函数
if __name__ == "__main__":
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 8888))
server_socket.listen(128)
while True:
client_socket, client_address = server_socket.accept()
print("[%s, %s]用户连接上了" % client_address)
handle_client_process = Process(target=handle_socket, args=(client_socket,))
handle_client_process.start()
client_socket.close()
#接受数据,发送数据,关闭连接
request_data = client_socket.recv(20480)
request_data = str(request_data, encoding='utf-8')
outkey = pDll.LicenseCheckCal(int(need_key))
response_body = str(outkey)
client_socket.send(bytes(response_body, 'utf-8'))
client_socket.close()
#MySQL提交事务,也是很简单了
def lockedExecute(sql):
mysql_conn = pymysql.connect(host='127.0.0.1', port=3306, user='xxx', password='xxx', db='xxx')
try:
with mysql_conn.cursor() as cursor:
cursor.execute(sql)
mysql_conn.commit()
except Exception as e:
print(e)
mysql_conn.rollback()
finally:
mysql_conn.close()
//C++socket
#include <WinSock2.h>
//记得附加ws2_32.lib
//初始化
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建套接字
SOCKET clntSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//向服务器发送消息
sockaddr_in sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充
sockAddr.sin_family = PF_INET;
sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sockAddr.sin_port = htons(8888);
connect(clntSock, (SOCKADDR*)& sockAddr, sizeof(SOCKADDR));
//发送消息
string sendToServerBuffer = "";
send(clntSock, sendToServerBuffer.c_str(), sendToServerBuffer.size(), 0);
//接收服务器消息
char responseBuffer[64] = { 0 };
recv(clntSock, responseBuffer, 64, 0);
//关闭套接字
closesocket(clntSock);
//终止dll
WSACleanup();
//C++递归获取文件夹内所有带路径的文件名
void get_files(std::string fileFolderPath, std::string fileExtension, std::vector<std::string>&file)
{
std::string fileName;
struct _finddata_t fileInfo;
long long findResult;
if ((findResult = _findfirst((fileFolderPath + "\\*").c_str(), &fileInfo)) != -1) {
do {
if ((fileInfo.attrib&_A_SUBDIR))
{ //如果是文件夹;
if (strcmp(fileInfo.name, ".") != 0 && strcmp(fileInfo.name, "..") != 0)
{ //如果文件名不是.或者,,,则递归获取子文件中的文件;
get_files(fileFolderPath + "\\" + fileInfo.name, fileExtension, file); //递归子文件夹;
}
}
else //如果是文件;
{
int c;
c = strlen(fileInfo.name);
if (fileInfo.name[c - 3] == fileExtension[1] && fileInfo.name[c - 2] == fileExtension[2] && fileInfo.name[c - 1] == fileExtension[3])
{
file.push_back(fileFolderPath + "\\" + fileInfo.name);
}
}
memset(fileInfo.name, 0, sizeof(fileInfo.name));
} while (_findnext(findResult, &fileInfo) == 0);
_findclose(findResult);
}
}
C++的HTTP客户端直接参考mongoose示例代码即可。