客户端组织崩溃的 Winsocket 线程。
Winsocket threadding for Client organisation crashes.
主要思想是:
第一个线程只是等待客户端的连接。所以这个线程是一个管理器(communicationthread)。
一旦 accept == true,该线程就会创建另一个线程(线程向量),其中 recv 和 send 发生。
这是实现:
bool CServerClientCommunication::OpenConnectionForClient(int Port)
{
long rc;
SOCKADDR_IN addr;
rc=StartWinsock();
if(rc!=0)
{
return false;
}
server=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(server==INVALID_SOCKET)
{
return false;
}
memset(&addr,0,sizeof(SOCKADDR_IN));
addr.sin_family=AF_INET;
addr.sin_port=htons(Port);
addr.sin_addr.s_addr=ADDR_ANY;
rc=bind(server,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
if(rc==SOCKET_ERROR)
{
return false;
}
long rc2=listen(server,10);
if(rc2==SOCKET_ERROR)
{
return false;
}
WAIT_FOR_CLIENT:
if(Terminated)
{
return false;
}
// Accept Client to Serversocket
client=accept(server,NULL,NULL);
// Check if Accept failed
if(client==INVALID_SOCKET)
{
if( Clients.size()>0)
{
for (int i = 0; i < Clients.size(); i++)
{
if(Clients[i]->isKilled == true)
{
Clients[i]->Terminate();
Clients[i]->WaitFor();
delete Clients[i];
Clients[i] = NULL;
}
}
}
goto WAIT_FOR_CLIENT;
}
CServerClientProcessing * ServerClientProcessing = new CServerClientProcessing(true);
ServerClientProcessing->FreeOnTerminate = false;
Clients.push_back(ServerClientProcessing);
ServerClientProcessing->client = client;
Sleep(100);
if( Clients.size()>0)
{
for (int i = 0; i < Clients.size(); i++)
{
if(Clients[i]->isKilled == true)
{
Clients[i]->Terminate();
Clients[i]->WaitFor();
delete Clients[i];
Clients[i] = NULL;
}
}
}
ServerClientProcessing->Resume();
goto WAIT_FOR_CLIENT;
}
int CServerClientCommunication::StartWinsock()
{
WSADATA wsa;
return WSAStartup(MAKEWORD(2,0),&wsa);
}
bool CServerClientCommunication::GetConnectionStatus()
{
return server != -1;
}
//---------------------------------------------------------------------------
void __fastcall CServerClientCommunication::Execute()
{
int Port = PortProperties->ClientPort;
bool check=OpenConnectionForClient(Port);
}
我们在这里得到了一个执行接收和发送(处理线程)的线程向量。如果我们失去与客户端的通信,我们将 bool isKilled 设置为 true,因此通信线程可以在 vector 中终止该线程。
这是处理线程的实现:
void __fastcall CServerClientProcessing::Execute()
{
AnsiString Answer = "";
AnsiString CheckCase = "GetTemperature";
AnsiString CheckCase2 = "GetSetTemperature";
AnsiString ToSend = "";
AnsiString Error = "WRONG_ORDER";
AnsiString AllUp;
int ByteOffset = 0;
int Receive = 0;
int Send = 0;
char recvbuf[255];
while(!Terminated)
{
memset(recvbuf, 0x00, sizeof(recvbuf));
int StartTime = GetTickCount(); //100
ByteOffset = 0;
while(GetTickCount()-StartTime<1000 && !Terminated && isKilled == false)
{
// recv function to recieve information from server
// bitwise recieve information from client
Receive = recv(client,&recvbuf[ByteOffset],1,0);
// Receive > 0 true.
if (Receive > 0 )
{
// find last char \r and delete it
if(recvbuf[ByteOffset] == '\r')
{
recvbuf[ByteOffset] = '[=11=]' ;
AnsiString temp = recvbuf;
AllUp = recvbuf;
AllUp=AllUp.UpperCase();
break;
}
ByteOffset++;
}
if (Receive < 0)
{
int value = WSAGetLastError();
if (value == 10054 || value == 10093)
{
isKilled = true;
closesocket(client);
break;
}
else
continue;
}
if (Receive = 0)
{
isKilled = true;
closesocket(client);
break;
}
}
// check content of receive
if(AllUp.Length()!= NULL)
{
CheckCase = CheckCase.UpperCase();
if(AllUp == CheckCase)
{
ToSend = FloatToStr(ConnectionThread->CurrentTemperature/10.0);
Answer = ToSend + "\r";
// copy information into buffer to send the answer client
memcpy(recvbuf,Answer.c_str(), Answer.Length());
}
CheckCase2 = CheckCase2.UpperCase();
if( AllUp == CheckCase2)
{
ToSend = FloatToStr(ConnectionThread->TemperatureLimit1/10.0);
Answer = ToSend + "\r";
// copy information into buffer to send the answer client
memcpy(recvbuf,Answer.c_str(), Answer.Length());
}
if( AllUp == CheckCase && AllUp == CheckCase2 )
{
Error = Error + "\r";
memcpy(recvbuf,Error.c_str(), Error.Length());
}
}
else
{
Error = Error + "\r";
memcpy(recvbuf,Error.c_str(), Error.Length());
}
// send answer(buffer) to client
Send = send( client, recvbuf, sizeof(recvbuf), 0 );
Sleep(1000);
// check if failed sending
if (Send == SOCKET_ERROR)
{
closesocket(client);
isKilled = true;
WSACleanup();
break;
}
}
}
只要我打开客户端,一切正常。但是当我关闭客户端时,不想要的事情发生了:我无法连接另一个客户端并且新客户端死了。同时两个客户端也是不可能的。
是需要Critical section,还是结构的逻辑问题?由于删除了矢量,我也遇到了访问冲突,即使我检查它是否不为空。
我发现错误:
这是个糟糕的想法,因为我使用的是 TCP_Socket,这可以实现安全的信息传输。所以我要看资料
代替它,我在找到\r后就分手了。消息的其余部分,大约 230 个标志仍在通行。
这就是它断开连接的原因。我必须发送消息的长度而不是缓冲区的长度。
主要思想是:
第一个线程只是等待客户端的连接。所以这个线程是一个管理器(communicationthread)。 一旦 accept == true,该线程就会创建另一个线程(线程向量),其中 recv 和 send 发生。 这是实现:
bool CServerClientCommunication::OpenConnectionForClient(int Port)
{
long rc;
SOCKADDR_IN addr;
rc=StartWinsock();
if(rc!=0)
{
return false;
}
server=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(server==INVALID_SOCKET)
{
return false;
}
memset(&addr,0,sizeof(SOCKADDR_IN));
addr.sin_family=AF_INET;
addr.sin_port=htons(Port);
addr.sin_addr.s_addr=ADDR_ANY;
rc=bind(server,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
if(rc==SOCKET_ERROR)
{
return false;
}
long rc2=listen(server,10);
if(rc2==SOCKET_ERROR)
{
return false;
}
WAIT_FOR_CLIENT:
if(Terminated)
{
return false;
}
// Accept Client to Serversocket
client=accept(server,NULL,NULL);
// Check if Accept failed
if(client==INVALID_SOCKET)
{
if( Clients.size()>0)
{
for (int i = 0; i < Clients.size(); i++)
{
if(Clients[i]->isKilled == true)
{
Clients[i]->Terminate();
Clients[i]->WaitFor();
delete Clients[i];
Clients[i] = NULL;
}
}
}
goto WAIT_FOR_CLIENT;
}
CServerClientProcessing * ServerClientProcessing = new CServerClientProcessing(true);
ServerClientProcessing->FreeOnTerminate = false;
Clients.push_back(ServerClientProcessing);
ServerClientProcessing->client = client;
Sleep(100);
if( Clients.size()>0)
{
for (int i = 0; i < Clients.size(); i++)
{
if(Clients[i]->isKilled == true)
{
Clients[i]->Terminate();
Clients[i]->WaitFor();
delete Clients[i];
Clients[i] = NULL;
}
}
}
ServerClientProcessing->Resume();
goto WAIT_FOR_CLIENT;
}
int CServerClientCommunication::StartWinsock()
{
WSADATA wsa;
return WSAStartup(MAKEWORD(2,0),&wsa);
}
bool CServerClientCommunication::GetConnectionStatus()
{
return server != -1;
}
//---------------------------------------------------------------------------
void __fastcall CServerClientCommunication::Execute()
{
int Port = PortProperties->ClientPort;
bool check=OpenConnectionForClient(Port);
}
我们在这里得到了一个执行接收和发送(处理线程)的线程向量。如果我们失去与客户端的通信,我们将 bool isKilled 设置为 true,因此通信线程可以在 vector 中终止该线程。 这是处理线程的实现:
void __fastcall CServerClientProcessing::Execute()
{
AnsiString Answer = "";
AnsiString CheckCase = "GetTemperature";
AnsiString CheckCase2 = "GetSetTemperature";
AnsiString ToSend = "";
AnsiString Error = "WRONG_ORDER";
AnsiString AllUp;
int ByteOffset = 0;
int Receive = 0;
int Send = 0;
char recvbuf[255];
while(!Terminated)
{
memset(recvbuf, 0x00, sizeof(recvbuf));
int StartTime = GetTickCount(); //100
ByteOffset = 0;
while(GetTickCount()-StartTime<1000 && !Terminated && isKilled == false)
{
// recv function to recieve information from server
// bitwise recieve information from client
Receive = recv(client,&recvbuf[ByteOffset],1,0);
// Receive > 0 true.
if (Receive > 0 )
{
// find last char \r and delete it
if(recvbuf[ByteOffset] == '\r')
{
recvbuf[ByteOffset] = '[=11=]' ;
AnsiString temp = recvbuf;
AllUp = recvbuf;
AllUp=AllUp.UpperCase();
break;
}
ByteOffset++;
}
if (Receive < 0)
{
int value = WSAGetLastError();
if (value == 10054 || value == 10093)
{
isKilled = true;
closesocket(client);
break;
}
else
continue;
}
if (Receive = 0)
{
isKilled = true;
closesocket(client);
break;
}
}
// check content of receive
if(AllUp.Length()!= NULL)
{
CheckCase = CheckCase.UpperCase();
if(AllUp == CheckCase)
{
ToSend = FloatToStr(ConnectionThread->CurrentTemperature/10.0);
Answer = ToSend + "\r";
// copy information into buffer to send the answer client
memcpy(recvbuf,Answer.c_str(), Answer.Length());
}
CheckCase2 = CheckCase2.UpperCase();
if( AllUp == CheckCase2)
{
ToSend = FloatToStr(ConnectionThread->TemperatureLimit1/10.0);
Answer = ToSend + "\r";
// copy information into buffer to send the answer client
memcpy(recvbuf,Answer.c_str(), Answer.Length());
}
if( AllUp == CheckCase && AllUp == CheckCase2 )
{
Error = Error + "\r";
memcpy(recvbuf,Error.c_str(), Error.Length());
}
}
else
{
Error = Error + "\r";
memcpy(recvbuf,Error.c_str(), Error.Length());
}
// send answer(buffer) to client
Send = send( client, recvbuf, sizeof(recvbuf), 0 );
Sleep(1000);
// check if failed sending
if (Send == SOCKET_ERROR)
{
closesocket(client);
isKilled = true;
WSACleanup();
break;
}
}
}
只要我打开客户端,一切正常。但是当我关闭客户端时,不想要的事情发生了:我无法连接另一个客户端并且新客户端死了。同时两个客户端也是不可能的。
是需要Critical section,还是结构的逻辑问题?由于删除了矢量,我也遇到了访问冲突,即使我检查它是否不为空。
我发现错误:
这是个糟糕的想法,因为我使用的是 TCP_Socket,这可以实现安全的信息传输。所以我要看资料
代替它,我在找到\r后就分手了。消息的其余部分,大约 230 个标志仍在通行。
这就是它断开连接的原因。我必须发送消息的长度而不是缓冲区的长度。