客户端组织崩溃的 Winsocket 线程。

Winsocket threadding for Client organisation crashes.

主要思想是:

第一个线程只是等待客户端的连接。所以这个线程是一个管理器(communicationthread)。 一旦 accept == true,该线程就会创建另一个线程(线程向量),其中 recvsend 发生。 这是实现:

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 个标志仍在通行。

这就是它断开连接的原因。我必须发送消息的长度而不是缓冲区的长度。