Avatar billede dewalth Nybegynder
16. januar 2007 - 23:20 Der er 3 kommentarer

serversocket fejler når klienter fjernes uden disconnect

Hey

Jeg har lavet et chat program baseret på borlands eksempel, det der ligger i Cbuilder6.
Det spiller også max. Problemet opstår når en af klienterne logger af uden at sige ”pænt” farvel til serven.
Eksempel vis hvis man lukker klienten fra proceslisten. Når serveren så skal sende ud til klienterne igen sender også til den klient som ikke længere findes, dette resultere at serveren går ned.

Jeg kan detektere at der er opstået en fejl. Men hvordan får jeg slettet forbindelsen til den klient som er blevet ”væk”??

Serveren kører ”stNonBloking”.

/Peter
Avatar billede quiw Nybegynder
17. januar 2007 - 17:00 #1
Når klienten lukker uden at sende et "farvel", så sker der det at dit receive loop begynder at kører uendeligt, fordi den bare modtager "\0" konstant, så derfor kan du f.eks. gøre således at hvis inputtet fra dit receive er == \0 så skal den udføre et closesocket(ID).
Avatar billede dewalth Nybegynder
01. februar 2007 - 15:31 #2
Har været lidt væk fra PC men er tilbage nu.
Det du skriver, giver god mening men jeg kan ikke lige se hvordan det kan implementeres. Derfor lige lidt server kode.
Har prøvet at lave noget ligende dit forslag nede i MyServerClientError eventen.

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TServerSocket *MyServer;

TStringList *UserName = new TStringList(); // Der oprettes en pointer der
                                          //kaldes UserName.
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
MyServer = new TServerSocket(Form1);
MyServer->OnClientConnect = MyServerClientConnect;
MyServer->OnClientDisconnect = MyServerClientDisconnect;
MyServer->OnClientRead = MyServerClientRead;
MyServer->OnClientError = MyServerClientError;

ConnectedList = new TStringList();
//FileName = "log.txt"

}
//------------------------------------------------------------------------------
void __fastcall TForm1::StartButtonClick(TObject *Sender)
{
MyServer->Port = PortEdit->Text.ToIntDef(5200); // Sætter porten
                                               
Caption = MyServer->Port; // Sætter caption til port nr
MyServer->Active = true; // Aktivere server
StopButton->Enabled = true; // Gør Stopknappen synlig
StartButton->Enabled = false; // Gør Startknappen usynlig
PortEdit->Enabled = false; // Gør at ændring af port ikke er mulig
//LogMemo->Lines->LoadFromFile("log.txt"); // Loader log.txt ved start af server
}
//------------------------------------------------------------------------------
void __fastcall TForm1::StopButtonClick(TObject *Sender)
{
MyServer->Active = false; // Deaktivere server
StartButton->Enabled = true; // Gør Startknappen synlig
StopButton->Enabled = false; // Gør Stopknappen usynlig
PortEdit->Enabled = true; // Gør at det er muligt at ændre port
}
//------------------------------------------------------------------------------
void __fastcall TForm1::MyServerClientConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
LogMemo->Lines->Add(Socket->RemoteAddress + " has connected.");
// Den skriver på skærmen hvem der har connected.
ConnectedList->AddObject(Socket->RemoteAddress, Socket);
// Opdaterer ConnectedList.
}
//------------------------------------------------------------------------------
void __fastcall TForm1::MyServerClientDisconnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
AnsiString bruger = Format("%s",OPENARRAY(TVarRec,(ConnectedList->Strings[ConnectedList->IndexOfObject(Socket)])));
int slet_socket = Memoadr->Lines->IndexOf(ConnectedList->IndexOfObject(Socket));

LogMemo->Lines->Add(Socket->RemoteAddress + " er logget af.");
SendMessage(Format("%s er logget af.",
  OPENARRAY(TVarRec,
  (ConnectedList->Strings[ConnectedList->IndexOfObject(Socket)]))), "Server");
  // Den skriver på skærmen hvem der har Disconnected
ConnectedList->Delete(ConnectedList->IndexOfObject(Socket));
  // Opdatere ConnectedList


int slet_bruger = UserMemo->Lines->IndexOf(bruger);
if(slet_bruger != -1) {
  UserMemo->Lines->Delete(slet_bruger);
  Memoadr->Lines->Delete(slet_socket);
  Timer->Enabled = true;
}
}
//------------------------------------------------------------------------------
void __fastcall TForm1::SendMessage(AnsiString aMessage, AnsiString aForm)
{
AnsiString besked;
AnsiString error;

for(int i = 0;i<MyServer->Socket->ActiveConnections;i++)
                       
  {
  if(aForm == "Server") {//Hvis serveren skal sende noget
    MyServer->Socket->Connections[i]->SendText(
    error = Format("%s", OPENARRAY(TVarRec,(aMessage))));
  }
  else { //hvis brugeren sender beskeden
    MyServer->Socket->Connections[i]->SendText(
    Format("%s sagde: %s", OPENARRAY(TVarRec,(aForm, aMessage))));

  }
    besked = Format("%s sagde: %s", OPENARRAY(TVarRec,(aForm, aMessage)));
    LogMemo->Lines->Add(besked);
  }
}
//------------------------------------------------------------------------------
void __fastcall TForm1::MyServerClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
try {


bool commando = false;
AnsiString TextIn, CurrentName;
int iIndex;

//ConnectedList->BeginUpdate();
TextIn = Socket->ReceiveText();

iIndex = ConnectedList->IndexOfObject(Socket); 

if(TextIn == "\0") {
  MyServer->Socket->Disconnect(iIndex);
}

if(iIndex == -1 )  // Hvis brugeren er disconnected
  return;



if(TextIn.Pos("UserName=") == 1)
{
  //Set User Name
  UserName->Text = TextIn; // User Name oprettes
  ConnectedList->Strings[iIndex] = UserName->Values["UserName"];
  UserMemo->Lines->Add(UserName->Values["UserName"]);
  Memoadr->Lines->Add(ConnectedList->IndexOfObject(Socket));
  SendMessage(Format("%s er logget på.",
              OPENARRAY(TVarRec,
                          (UserName->Values["UserName"]))),"Server");
                          // User name skrives på skærmen efterfulgt af has
                          // connected. User Name placeres i
  SendUsers("");
  commando = true;
}

if(TextIn.Pos("<specuser>") == 1) {
  AnsiString Tekst = TextIn;
  int spect = NULL;

  spect = Tekst.SubString(Tekst.Pos("<specuser>")+10,Tekst.Pos("</specuser>")-11).ToInt();
  //LogMemo->Lines->Add(spect);
  AnsiString Texttilspec = Tekst.SubString(Tekst.Pos("</specuser>")+11,(Tekst.Length()-(Tekst.Pos("</specuser>")+10)));
  CurrentName = ConnectedList->Strings[iIndex];
  SendMessageSpec(Texttilspec, CurrentName, spect);
}
else
{
  if(!commando) {
  //Send Message
  CurrentName = ConnectedList->Strings[iIndex];
  SendMessage(TextIn, CurrentName);
  Label->Caption = MyServer->Socket->ActiveConnections;
  }
}
}// try
catch (...) {
  MessageBox(0, "", "FEJL", MB_ICONINFORMATION|MB_OK);
}
//delete UserName;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SendUsers(AnsiString disconnedusers)
{
AnsiString userlist = "";
int usersconneted = UserMemo->Lines->Count;

for (int i = 0; i < usersconneted; i++) {
  if (i == 0) {
  userlist = "";
  }
  userlist += "<user>";
  userlist += UserMemo->Lines->operator [](i);
  userlist += "</user>";
}
SendMessage(Format("UserList=%s ",OPENARRAY(TVarRec,(userlist))),"Server");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TimerTimer(TObject *Sender)
{
Timer->Enabled = false;
SendUsers("bruger");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SendMessageSpec(AnsiString aMessage, AnsiString aForm, int aResiver)
{
MyServer->Socket->Connections[aResiver]->SendText(
Format("%s sagde til dig: %s", OPENARRAY(TVarRec,(aForm, aMessage))));
}
//---------------------------------------------------------------------------
void __fastcall TForm1::MyServerClientError(TObject *Sender,
      TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{

AnsiString error = ErrorCode;
ErrorCode = 0;
int iIndex;
iIndex = ConnectedList->IndexOfObject(Socket);
AnsiString TextIn = Socket->ReceiveText();


if(TextIn == "\0") {
  MyServer->Socket->Disconnect(iIndex);
}

}
//--------------------------------------------------------------------------
void __fastcall TForm1::ButtonClick(TObject *Sender)
{
Memo->Lines->Clear();
for (int i = 1; i <= ConnectedList->Count; i++) {
  Memo->Lines->Add(ConnectedList->Strings[i-1]);
}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
  Memo->Lines->Clear();
for (int i = 1; i <= MyServer->Socket->ActiveConnections; i++) {
  String test = "false";
  if (MyServer->Socket->Connections[i-1]->Connected == true)
    test = "true";
  Memo->Lines->Add(test);
}
}
//---------------------------------------------------------------------------
Avatar billede quiw Nybegynder
13. august 2008 - 14:26 #3
Altså, jeg har ikke så meget forstand på C++ igen, men  med at lukke på \0 løste mit eget problem da jeg lavede noget lignende .. Men kan en timeout på en socket ikke være en løsning?

Men er det ikke forholdsvist simpelt?  Hvor henne i koden modtager du inputtet? Når du modtager inputtet, tjekker du om inputtet er == '\0' .. Hvis sandt, så luk forbindelsen, ellers fortsæt :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester