问题描述
所以我的类的对象指针有一些问题,并且不断被函数覆盖。为了帮助您理解,这是一个旨在帮助人们轻松地从客户端与服务器建立 winsock 套接字连接的库的项目。
Main.cpp:
(includes aleready included)
int main() {
Client client;
//AUTH SERVER
client.WSA_init(2,2);
SOCKET server_auth = client.init("127.0.0.1",3211);
std::string auth = client.ClientRecieve(server_auth);
std::string hash = client.Auth(auth);
client.End(server_auth);
client.WSA_init(2,2);
SOCKET server_main = client.init("127.0.0.1",3212);
client.ClientSend(server_main,(char*)hash.c_str());
ClientSocketParameters* t_params = new ClientSocketParameters; //Basically a parameter object pointer
t_params->Recv_BufferAccesibilityMode = THREAD_CONSOLE_PRINT_INFO; //These are defined aleready as macros in the win32s.h file
t_params->Recv_Raw = false;
t_params->Recv_Server_Type = SERVER_TYPE_JAVA;
t_params->Send_Mode = THREAD_KEYBOARD_SEND;
t_params->Send_Raw = false;
t_params->Send_Server_Type = SERVER_TYPE_JAVA;
client.setThreadParameters(t_params); //Sets the params
DWORD tid;
ThreadHandler::Socket_CallBack* t_recv = new ThreadHandler::Socket_CallBack;
t_recv->client = &client;
t_recv->socket = server_main;
ThreadHandler::Socket_CallBack* t_send = new ThreadHandler::Socket_CallBack;
t_send->client = &client;
t_send->socket = server_main;
HANDLE h1 = CreateThread(nullptr,NULL,ThreadHandler::ThreadClientRecieve,&t_recv,&tid); //Launches functions that are starting recv and sending with infinity loop (cant put here a client method so needed to do this (btw. these are also in the win32s files))
HANDLE h2 = CreateThread(nullptr,ThreadHandler::ThreadClientSend,&t_send,&tid);
WaitForSingleObject(h1,INFINITE);
WaitForSingleObject(h2,INFINITE);
client.End(server_main);
return 0;
}
win32_s.h 文件:
(includes aleready included)
class ClientSocketParameters { //Parameter class
public:
//Recieving
DWORD Recv_BufferAccesibilityMode;
bool Recv_Raw;
DWORD Recv_Server_Type;
std::string* Recv_StoreAddress;
char* Recv_StoreAdress_Raw;
//Sending
DWORD Send_Mode;
bool Send_Raw;
DWORD Send_Server_Type;
std::string* Send_StoredDataAddress;
};
class Client {
private:
ClientSocketParameters* thread_settings = new ClientSocketParameters; //This is the pointer that is getting overwritten. It is basically a pointer to the parameters that you set with a method in your main
SOCKET init(std::string ip,int port); //Most of these functions are not necessary for problem cause
WSAData WSA_init(int version_makeword_1,int version_makeword_2);
std::string Auth(std::string key);
int PackageManager(); //Todo
int ClientSend(SOCKET dst,char buffer[]);
std::string ClientRecieve(SOCKET src);
std::string BufferToString(char buffer[]);
std::string BufferToJavaString(char buffer[]);
std::string JavaBufferToString(char buffer[]);
int End(SOCKET con);
Some macros
void setThreadParameters(ClientSocketParameters* params);
DWORD WINAPI Thread_ClientRecieve(LPVOID socket_src);
DWORD WINAPI Thread_ClientSend(LPVOID dst);
};
namespace ThreadHandler { //These lauches the thread functions with calling them (check .cpp of this file)
DWORD WINAPI ThreadClientRecieve(LPVOID param);
DWORD WINAPI ThreadClientSend(LPVOID param);
struct Socket_CallBack {
SOCKET socket;
Client* client;
};
}
win32_s.cpp 文件:
#include "win32_s.h"
(I'm not going to show the not necessary functions that work)
void Client::setThreadParameters(ClientSocketParameters* params) {
std::cout << params << std::endl;
thread_settings = params;
std::cout << thread_settings << std::endl; //This address is correct to this point,The Thread_ClientRecieve and the thread send function overwrites the address to 0x11C when checking the variables of the pointer
}
DWORD WINAPI Client::Thread_ClientRecieve(LPVOID lpParam) { //Todo: Packet management,Exceptions
const DWORD MAX_BYTES = 1024;
char buffer[MAX_BYTES];
size_t recvbytes;
SOCKET server = *(SOCKET*)lpParam;
while (true) {
//std::cout << "here #packet recieve" << std::endl;
ZeroMemory(buffer,MAX_BYTES);
recvbytes = recv(server,buffer,MAX_BYTES,0);
if (recvbytes <= 0) {
std::cout << "Recieving info from server Failed. Cancellig thread..." << std::endl;
break;
}
std::cout << thread_settings->Recv_BufferAccesibilityMode << std::endl;
std::cout << thread_settings->Recv_Raw << std::endl;
std::cout << thread_settings->Recv_Server_Type << std::endl;
if (thread_settings->Recv_BufferAccesibilityMode == THREAD_CONSOLE_PRINT_INFO) {
std::string console_text;
if (thread_settings->Recv_Raw) {
std::cout << buffer << std::endl;
}
if (thread_settings->Recv_Server_Type == SERVER_TYPE_JAVA) {
console_text = JavaBufferToString(buffer);
std::cout << console_text << std::endl;
}
if (thread_settings->Recv_Server_Type == SERVER_TYPE_WINSOCK) {
console_text = BufferToString(buffer);
std::cout << console_text << std::endl;
}
}
if (thread_settings->Recv_BufferAccesibilityMode == THREAD_STORE_INFO) {
std::string buffer_s;
if (thread_settings->Recv_Raw) {
thread_settings->Recv_StoreAdress_Raw = buffer;
}
if (thread_settings->Recv_Server_Type == SERVER_TYPE_JAVA) {
buffer_s = JavaBufferToString(buffer);
*thread_settings->Recv_StoreAddress = buffer_s;
}
if (thread_settings->Recv_Server_Type == SERVER_TYPE_WINSOCK) {
buffer_s = BufferToString(buffer);
*thread_settings->Recv_StoreAddress = buffer_s;
}
}
}
return 0;
}
DWORD WINAPI Client::Thread_ClientSend(LPVOID lpParam) {
const DWORD MAX_BYTES = 1024;
char buffer[1024];
SOCKET server = *(SOCKET*)lpParam;
while (true) {
//std::cout << "here #send packet" << std::endl;
if (thread_settings->Send_Mode == THREAD_KEYBOARD_SEND) {
std::cin.getline(buffer,1024);
std::string data;
if (thread_settings->Send_Raw) {
if (send(server,0) == SOCKET_ERROR) {
std::cout << "Failed while sending to the server. Closing thread...." << std::endl;
return -1;
}
}
if (thread_settings->Send_Server_Type == SERVER_TYPE_JAVA) {
data = BufferToJavaString(buffer);
if (send(server,data.c_str(),data.size(),0) == SOCKET_ERROR) {
std::cout << "Failed while sending to the server. Closing thread...." << std::endl;
return -1;
}
}
if (thread_settings->Send_Server_Type == SERVER_TYPE_WINSOCK) {
data = BufferToString(buffer);
if (send(server,0) == SOCKET_ERROR) {
std::cout << "Failed while sending to the server. Closing thread...." << std::endl;
return -1;
}
}
}
if (thread_settings->Send_Mode == THREAD_VARIABLE_SEND) {
if (thread_settings->Send_StoredDataAddress == NULL) {
std::cout << "Please enter a address to use the thread variable send function. Cancelling thread..." << std::endl;
return -1;
}
//memset(thread_settings.Send_StoredDataAddress,0x90,sizeof(thread_settings.Send_StoredDataAddress));
std::string StoredData = *thread_settings->Send_StoredDataAddress;
if (thread_settings->Send_Server_Type == SERVER_TYPE_JAVA) {
StoredData.append("\n");
if (send(server,StoredData.c_str(),StoredData.size(),0) == SOCKET_ERROR) {
std::cout << "Failed while sending to the server. Closing thread...." << std::endl;
return -1;
}
}
else {
if (send(server,0) == SOCKET_ERROR) {
std::cout << "Failed while sending to the server. Closing thread...." << std::endl;
return -1;
}
}
}
}
}
DWORD WINAPI ThreadHandler::ThreadClientRecieve(LPVOID param) {
Socket_CallBack* s_callback = new Socket_CallBack;
s_callback = (Socket_CallBack*)param;
SOCKET socket = s_callback->socket;
Client* callback_ptr = new Client;
callback_ptr = s_callback->client;
//delete s_callback;
//delete &s_callback->client;
std::cout << "ClientRecvSocketAddr: " << socket << std::endl;
std::cout << "ClientCallBackPtr: " << callback_ptr << std::endl;
return callback_ptr->Thread_ClientRecieve((LPVOID)socket);
}
DWORD WINAPI ThreadHandler::ThreadClientSend(LPVOID param) {
Socket_CallBack* s_callback = new Socket_CallBack;
s_callback = (Socket_CallBack*)param;
SOCKET socket = s_callback->socket;
Client* callback_ptr = new Client;
callback_ptr = s_callback->client;
//delete s_callback;
//delete &s_callback->client;
std::cout << "ClientSendSocketAddr: " << socket << std::endl;
std::cout << "ClientCallBackPtr: " << callback_ptr << std::endl;
return callback_ptr->Thread_ClientSend((LPVOID)socket);
}
这段代码还没有完全完成,所以像检查和更小的细节这样的事情还没有实现。 感谢您提供任何帮助并利用您的时间。
解决方法
我认为问题出在这里
SOCKET server_main = client.init("127.0.0.1",3212);
...
HANDLE h1 = CreateThread(nullptr,NULL,ThreadHandler::ThreadClientRecieve,&server_main,&tid);
HANDLE h2 = CreateThread(nullptr,ThreadHandler::ThreadClientSend,&tid);
您创建了两个线程,将指向 SOCKET
的指针作为参数传递。
但是在线程代码中,您将该参数转换为 Client
指针。
DWORD WINAPI ThreadHandler::ThreadClientSend(LPVOID param) {
Client* ptr = (Client*)param;
return ptr->Thread_ClientSend(param);
}
毫不奇怪,将真正是 SOCKET*
的内容转换为 Client*
是行不通的。
我猜代码应该是这样的
HANDLE h1 = CreateThread(nullptr,&client,&tid);
编辑所以仍然存在各种问题
这段代码没有错,只是浪费(和混乱)
DWORD WINAPI ThreadHandler::ThreadClientRecieve(LPVOID param) {
Socket_CallBack* s_callback = new Socket_CallBack;
s_callback = (Socket_CallBack*)param;
SOCKET socket = s_callback->socket;
Client* callback_ptr = new Client;
callback_ptr = s_callback->client;
这里绝对不需要分配更多内存,Socket_CallBack
和Client
对象已经分配好了。此代码将工作
DWORD WINAPI ThreadHandler::ThreadClientRecieve(LPVOID param) {
Socket_CallBack* s_callback = (Socket_CallBack*)param;
SOCKET socket = s_callback->socket;
Client* callback_ptr = s_callback->client;
现在这是真正的错误
return callback_ptr->Thread_ClientRecieve((LPVOID)socket);
SOCKET
正在传递给 Thread_ClientRecieve
。但是当我们看到 Thread_ClientRecieve
DWORD WINAPI Client::Thread_ClientRecieve(LPVOID lpParam) {
...
SOCKET server = *(SOCKET*)lpParam;
参数被转换为 SOCKET*
。当您将一种类型转换为其他类型时,您必须转换回相同的类型。您不能将 SOCKET
转换回 SOCKET*
。
有两种方法可以解决这个问题,一种是最少的,一种是正确的方法(尽可能避免强制转换和指针)。
最简单的方法是传递socket的地址,像这样
return callback_ptr->Thread_ClientRecieve((LPVOID)&socket);
现在将 SOCKET*
传递给 Client::Thread_ClientRecieve
,因此您可以安全地将参数转换回 SOCKET*
。
但在这里我们可以简单地删除所有指针并通过将 Client::Thread_ClientRecieve
的参数更改为 SOCKET
,不进行强制转换,不进行指针转换。
DWORD WINAPI Client::Thread_ClientRecieve(SOCKET server) {
...
当你调用它时只传递套接字,不需要转换
return callback_ptr->Thread_ClientRecieve(socket);
发送代码看起来有类似的错误。