OnTimer event not work

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

OnTimer event not work

Postby mark_c » Wed Feb 26, 2020 2:48 am

I can't activate the OnTimer event but I don't see any problems, are there any?

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

class TMyThread : public TThread
{
private:
   void __fastcall MyTimer(TObject *Sender);
protected:
   void __fastcall Execute();
public:
   AnsiString myadr;
   AnsiString msg;
   __fastcall TMyThread(const String &Adr);
   void __fastcall MyMemo1();
};


int ThreadsRunning = 0;
bool Exiting = false;
int i;

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

__fastcall TMyThread::TMyThread(const AnsiString &Adr)
: TThread(true), myadr(Adr)
{
   FreeOnTerminate = true;
}
//---------------------------------------------------------------------------

void __fastcall TMyThread::MyMemo1()
{
   Form1->Memo1->Lines->Add(msg);
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::MyTimer(TObject *Sender)
{
   Form1->Memo3->Lines->Add("timer");
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{

   TTimer  *asd = new TTimer(NULL);
   asd->Interval = 500;
   asd->OnTimer = &MyTimer;
   asd->Enabled = true;

   msg = myip(StrToInt(myadr));
   Synchronize(&MyMemo1);
   Sleep(1000);
       
       delete asd;
}

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

void __fastcall TForm1::Button1Click(TObject *Sender)
{
   try
   {
      for(i = 0; i < 5; ++i)
      {
         TMyThread *TMyTh = new TMyThread(IntToStr(i+1));
         Memo2->Lines->Add("start: " + IntToStr(TMyTh->Handle));
         TMyTh->OnTerminate = &ThreadTerminated;
         TMyTh->Resume();
         Panel1->Caption=ThreadsRunning;
         ++ThreadsRunning;
      }
   } catch(...){ }

   Caption = "Start " + IntToStr(ThreadsRunning) + " threads created";
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ThreadTerminated(TObject *Sender)
{
   Memo1->Clear();
   Memo2->Clear();
   --ThreadsRunning;

   TMyThread *TMyTh = static_cast<TMyThread*>(Sender);
   Memo2->Lines->Add("old: " + IntToStr(TMyTh->Handle));
   TMyTh = new TMyThread(IntToStr(i++));
   Memo2->Lines->Add("new: " + IntToStr(TMyTh->Handle));
   TMyTh->OnTerminate = &ThreadTerminated;
   TMyTh->Resume();
   Panel1->Caption=ThreadsRunning;
   ++ThreadsRunning;

}
//---------------------------------------------------------------------------

mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby mark_c » Wed Feb 26, 2020 7:23 am

it is possible that the solution is simply adding

Code: Select all
     Application-> ProcessMessages ();


Code: Select all
void __fastcall TMyThread::Execute()
{

   TTimer  *asd = new TTimer(NULL);
   asd->Interval = 500;
   asd->OnTimer = &MyTimer;
   asd->Enabled = true;

   msg = myip(StrToInt(myadr));
   Synchronize(&MyMemo1);
   Sleep(1000);

   Application-> ProcessMessages ();   
 
    delete asd;
}

mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby rlebeau » Wed Feb 26, 2020 12:54 pm

Yes, the problem is due to the worker thread lacking a message loop to handle WM_TIMER messages for the TTimer's internal window. But, you should not use Application->ProcessMessages() in a worker thread, only in the main UI thread. In a worker thread, use a manual message loop instead.

Also, note that TTimer is signaled in the same thread context that its internal window is created in, which in your example is the worker thread, which means your OnTimer event handler will need to synchronize with the main UI thread when accessing UI controls.

Try this instead:

Code: Select all
void __fastcall TMyThread::MyMemo3()
{
    Form1->Memo3->Lines->Add(msg);
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::MyTimer(TObject *Sender)
{
    TTimer *asd = static_cast<TTimer*>(Sender);
    msg = "timer";
    Synchronize(&MyMemo3);
    asd->Tag = asd->Tag + 1;
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
    TTimer  *asd = new TTimer(NULL);
    asd->Interval = 500;
    asd->OnTimer = &MyTimer;
    asd->Enabled = true;
    asd->Tag = 0;

    msg = myip(StrToInt(myadr));
    Synchronize(&MyMemo1);

    MSG msg;
    while ((!Terminated) && (asd->Tag < 2) && (GetMessage(&msg, NULL, 0, 0) > 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
           
    delete asd;
}


On the other hand, you really should not use TTimer in a worker thread at all. It is a UI timer. There are better solutions for worker threads, such as using a waitable timer object instead, eg:

Code: Select all
void __fastcall TMyThread::Execute()
{
    msg = myip(StrToInt(myadr));
    Synchronize(&MyMemo1);

    HANDLE hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
    if (!hTimer) RaiseLastOSError();

    LARGE_INTEGER DueTime;
    DueTime.QuadPart = -5000000LL; // 500ms from now
    if (!SetWaitableTimer(hTimer, &DueTime, 500, NULL, NULL, FALSE))
    {
        DWORD err = GetLastError();
        CloseHandle(hTimer);
        RaiseLastOSError(err);
    }

    int count = 0;
    while ((!Terminated) && (count < 2) && (WaitForSingleObject(hTimer, INFINITE) == WAIT_OBJECT_0))
    {
        msg = "timer";
        Synchronize(&MyMemo3);
        ++count;
    }
           
    CancelWaitableTimer(hTimer);
    CloseHandle(hTimer);
}
Last edited by rlebeau on Fri Feb 28, 2020 3:25 pm, edited 1 time in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1665
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: OnTimer event not work

Postby mark_c » Thu Feb 27, 2020 5:13 am

thanks Remy,
I didn't understand this part
Code: Select all
asd->Tag = 0;

then I saw that if you don't use it, the timer continues indefinitely. So it is used to count the number of timer activations and when you have reached the desired number of activations, stop the thread; very interesting.
mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby mark_c » Fri Feb 28, 2020 7:17 am

I tried this version and I expected that after 3 seconds the socket would be closed but it doesn't work: what is the reason?
The purpose of the timer is to avoid waiting for 21 seconds before the timeout. As far as I have seen, there is no solution even with threads?
Code: Select all
void __fastcall TMyThread::MyTimer(TObject *Sender)
{
        msg="socket closed";
        Synchronize(&MyMemo1);
        asd->Tag = asd->Tag + 1; // number of uses of the timer

        MySock->Close();
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
   asd = new TTimer(NULL);
   asd->Interval = 1500;
   asd->OnTimer = &MyTimer;
   asd->Enabled = true;
   asd->Tag = 0;

   msg = myip(StrToInt(myadr));
   Synchronize(&MyMemo1);

   MySock = new TClientSocket(NULL);

   MySock->Address = "1.100.58.33";
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;

   MySock->Open();

   MSG mesg;
   while ((!Terminated) && (asd->Tag < 2) && (GetMessage(&mesg, NULL, 0, 0) > 0))
   {
      TranslateMessage(&mesg);
      DispatchMessage(&mesg);
   }

   delete asd;
}
mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby mark_c » Fri Feb 28, 2020 11:36 am

at this point is it not better to use the ctNonBlocking sockets and a timer for each thread or would it not make sense?
mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby rlebeau » Fri Feb 28, 2020 3:47 pm

mark_c wrote:I tried this version and I expected that after 3 seconds the socket would be closed


Why would you expect that? You are setting the timer to 1.5 seconds, and closing the socket on the first trigger of the timer. Why not just set the timer to 3 seconds instead?

mark_c wrote:but it doesn't work: what is the reason?


You are using a blocking socket in the same thread context as the timer. The thread's message loop will be blocked while the socket is busy, thus the timer will not be processed.

mark_c wrote:The purpose of the timer is to avoid waiting for 21 seconds before the timeout. As far as I have seen, there is no solution even with threads?


Sure, there is. Simply use a non-blocking socket instead (set TClientSocket::ClientType to ctNonBlocking), and then the message loop can handle both socket and timer at the same time, eg:

Code: Select all
void __fastcall TMyThread::MyTimer(TObject *Sender)
{
    msg = "socket connect timed out";
    Synchronize(&MyMemo1);
    MySock->Close();
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::MySockConnect(TObject* Sender, TCustomWinSocket* Socket)
{
    MySock->Tag = 0;
    msg = "socket connected";
    Synchronize(&MyMemo1);
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::MySockError(TObject* Sender, TCustomWinSocket* Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
    if (ErrorEvent == eeConnect)
    {
        MySock->Tag = 0;
        MySock->Close();
        msg = "socket failed to connect, error " + IntToStr(ErrorCode);
        ErrorCode = 0;
        Synchronize(&MyMemo1);
    }
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
    msg = myip(StrToInt(myadr));
    Synchronize(&MyMemo1);

    asd = new TTimer(NULL);
    asd->Interval = 3000;
    asd->OnTimer = &MyTimer;

    MySock = new TClientSocket(NULL);
    MySock->Address = "1.100.58.33";
    MySock->Port = 80;
    MySock->ClientType = ctNonBlocking;
    MySock->OnConnect = &MySockConnect;
    MySock->OnError = &MySockError;

    MySock->Open();
    MySock->Tag = 1;
    asd->Enabled = true;

    MSG mesg;
    while ((!Terminated) && (MySock->Tag == 1) && (GetMessage(&mesg, NULL, 0, 0) > 0))
    {
        TranslateMessage(&mesg);
        DispatchMessage(&mesg);
    }

    asd->Enabled = false;

    if (MySock->Active)
    {
        //...
    }

    delete MySock;
    delete asd;
}


In which case, there is no reason for this to be in a worker thread at all, it will work the same if used in the UI thread instead (which is what non-blocking mode was designed for).

However, non-blocking is considerable more difficult to write code for when dealing with reads/writes. So I would strongly suggest not using TClientSocket in a worker thread at all. You are better off just using the Winsock API directly. That way, you can create a socket, put it into non-blocking mode before connecting, start the connect and use the select() function to handle the timout, then switch the socket back to blocking mode if the connection is successful. TClientSocket does not let you do that.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1665
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: OnTimer event not work

Postby mark_c » Sat Feb 29, 2020 4:48 am

thanks Remy as always.
What I want to learn is to handle non-blocking socket events using threads, for example 20 threads running simultaneously and each time one thread ends, another runs with a new IP address.
That's why I asked you about the timer.

Initially, thanks to your numerous examples, I tried with blocking sockets but when an address that does not respond, the thread blocks for 21 seconds and from what I understand, there is no way to close the socket that is blocked at that moment .

Now I have moved on to non-blocking sockets with threads but I ask you: is it a complex way to manage treads and non-blocking sockets?

From my first experiments I realized that data is being lost but I still don't explain why.


this is the code i am using to read on socket ctNonBlocking implemented in a thread
Code: Select all
void __fastcall TMyThread::MySocketRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
        AnsiString MyBuffer;
        char Buf[1024];

        do
        {
                int ByteReceived = MySock->Socket->ReceiveBuf(Buf, sizeof(Buf));

                if (ByteReceived < 0)
                        return;

                if (ByteReceived == 0)
                        break;

                MyBuffer += AnsiString(Buf, ByteReceived);

                int Term = MyBuffer.Pos("\r\n0\r\n\r\n");
                if (Term != 0)
                {
                        MyBuffer.SetLength(Term-1);

                        FILE *fp;
                        AnsiString fname="dirout\\" + myadr + ".txt";
                        fp=fopen(fname.c_str(),"w");
                        fprintf(fp,"(%s)\n%s",nv,myadr.c_str(),MyBuffer.c_str());
                        fclose(fp);

                        break;
                }
        }
        while(true);

        if(MySock->Active)
                MySock->Close();

        delete MySock;
}
mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby rlebeau » Sat Feb 29, 2020 7:57 pm

mark_c wrote:What I want to learn is to handle non-blocking socket events using threads


I really do not suggest using non-blocking I/O in a worker thread. Blocking mode works better.

mark_c wrote:for example 20 threads running simultaneously and each time one thread ends, another runs with a new IP address.


I've already shown you earlier how to handle that, regardless of what the thread does internally.

mark_c wrote:Initially, thanks to your numerous examples, I tried with blocking sockets but when an address that does not respond, the thread blocks for 21 seconds


It blocks for however long the OS needs it to block until the OS knows whether the connection will succeed or not.

mark_c wrote:from what I understand, there is no way to close the socket that is blocked at that moment.


It is true to say that there is no way to make a blocking connect time out, but it is not true to say that there is no way to close the socket while it is blocked. There are ways to do it.

mark_c wrote:Now I have moved on to non-blocking sockets with threads but I ask you: is it a complex way to manage treads and non-blocking sockets?


It is complex to handle a non-blocking socket - period. Regardless of whether it is being used in a worker thread or not. I have posted MANY examples over the years in various forums showing how to code non-blocking socket I/O, using TClientSocket or Winsock directly. It is not trivial. Using blocking sockets makes things much simpler.

mark_c wrote:From my first experiments I realized that data is being lost but I still don't explain why. this is the code i am using to read on socket ctNonBlocking implemented in a thread


When Socket->ReceiveBuf() fails with a WSAEWOULDBLOCK error, indicating that your reading loop has exhausted all of the data in the socket's buffer, you 'return' from the handler, which is fine, but you also discard all of the data you cached in the MyBuffer variable, so it is no longer available when the OnRead event is fired again with more data. You need to make the MyBuffer variable be a member of the TMyThread class (or store it inside the TCustomWinSocket object itself, via its Data property) so it persists across multiple firings of the OnRead event.

Also, you can't 'delete' the TClientSocket from inside its own event.
Last edited by rlebeau on Sun Mar 01, 2020 2:57 pm, edited 2 times in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1665
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: OnTimer event not work

Postby mark_c » Sun Mar 01, 2020 2:15 am

thanks Remy, I understand that it is complex to manage ctNonBlocking sockets in the working threads but I want to learn this too.
You tell me you can't call this up within an event
Code: Select all
if (MySock-> Active)
        MySock-> Close ();

delete MySock;

however I don't understand why an exception is not thrown.

Anyway, thanks to all your numerous examples and tips, I moved MyBuffer inside the class and I don't lose any more data. Now I am using ctNonBlocking sockets within 50 worker threads and it seems to work all and without data loss.
I have implemented all the events of the OnConnect sockets, OnRead etc ... and I use the data send and receive cycles as you have shown me, and everything seems to work for now.
Thanks again

If you want to show me how to close a ctBlocking connection, thank you, I have searched but I have not found anything.
mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby rlebeau » Sun Mar 01, 2020 3:01 pm

mark_c wrote:You tell me you can't call this up within an event
Code: Select all
if (MySock-> Active)
        MySock-> Close ();

delete MySock;



I did NOT say there is a problem calling Close() on the socket object in a socket event. That is PERFECTLY FINE.

I said there IS a problem calling 'delete' on the socket object in a socket event. That is NOT OK. The RTL still needs access to the socket object after the event handler exits, so you can't 'delete' it from there.

mark_c wrote:however I don't understand why an exception is not thrown.


Why do you think an exception should be thrown? It is undefined behavior, anything can happen, or nothing at all.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1665
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: OnTimer event not work

Postby mark_c » Sun Mar 01, 2020 3:15 pm

Sorry I misunderstood
mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby mark_c » Mon Mar 02, 2020 3:02 am

rlebeau wrote:
mark_c wrote:from what I understand, there is no way to close the socket that is blocked at that moment.


It is true to say that there is no way to make a blocking connect time out, but it is not true to say that there is no way to close the socket while it is blocked. There are ways to do it.



if you want to show me how to abort after 5 seconds connections made with blocking sockets so as not to wait 21 seconds, thank you, I have not succeeded.
Sorry again for the bad understanding.
mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Re: OnTimer event not work

Postby rlebeau » Mon Mar 02, 2020 1:47 pm

mark_c wrote:if you want to show me how to abort after 5 seconds connections made with blocking sockets so as not to wait 21 seconds, thank you, I have not succeeded.


As I already told you earlier, you can put the socket into non-blocking mode, do the connect, and if successful then put the socket back into blocking mode.

But, to do that with TClientSocket is a little tricky, because of the way TClientSocket handles its ClientType property internally. The ClientType cannot be changed while the TClientSocket is active. So what you would have to do is

  • set the ClientType property to ctBlocking.
  • in the OnConnecting event, which is fired immediately before the Winsock connect() function is called, you can put the socket into non-blocking mode using the Winsock ioctlsocket() function.
  • in the OnConnect event, which is fired immediately after the Winsock connnect() function exits, you can handle the timeout as needed, such as with the Winsock select() function, and then put the socket back into blocking mode via ioctlsocket() if the connect succeeds without timeout.

For example:

Code: Select all
#include <RTLConsts.hpp>
...
//---------------------------------------------------------------------------
void __fastcall TMyThread::MySockConnecting(TObject* Sender, TCustomWinSocket* Socket)
{
    msg = "socket connecting";
    Synchronize(&MyMemo1);

    u_long nonBlocking = 1;
    if (ioctlsocket(Socket->SocketHandle, FIONBIO, &nonBlocking) == SOCKET_ERROR)
    {
        int err = WSAGetLastError();
        throw ESocketError(Rtlconsts_sWindowsSocketError, ARRAYOFCONST(( SysErrorMessage(err), err, "ioctlsocket")));
    }
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::MySockConnect(TObject* Sender, TCustomWinSocket* Socket)
{
    fd_set wfd, efd;

    FD_ZERO(&wfd);
    FD_SET(Socket->SocketHandle, &wfd);

    FD_ZERO(&efd);
    FD_SET(Socket->SocketHandle, &efd);

    timeval timeout;
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    int err = select(0, NULL, &wfd, &efd, &timeout);
    if (err <= 0)
    {
        if (err == SOCKET_ERROR)
            err = WSAGetLastError();
        else
            err = WSAETIMEDOUT;
    }
    else if (FD_ISSET(Socket->SocketHandle, &efd))
    {
        getsockopt(Socket->SocketHandle, SOL_SOCKET, SO_ERROR, (char*)&err, sizeof(err));
    }
    else
        err = 0;

    if (err != 0)
    {
        int tmpErr = err;
        MySockError(Sender, Socket, eeConnect, tmpErr);
        throw ESocketError(Rtlconsts_sWindowsSocketError, ARRAYOFCONST(( SysErrorMessage(err), err, "connect")));
    }

    msg = "socket connected";
    Synchronize(&MyMemo1);

    u_long nonBlocking = 0;
    if (ioctlsocket(Socket->SocketHandle, FIONBIO, &nonBlocking) == SOCKET_ERROR)
    {
        err = WSAGetLastError();
        throw ESocketError(Rtlconsts_sWindowsSocketError, ARRAYOFCONST(( SysErrorMessage(err), err, "ioctlsocket")));
    }
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::MySockError(TObject* Sender, TCustomWinSocket* Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
    if (ErrorEvent == eeConnect)
    {
        MySock->Close();
        msg = "socket failed to connect, error " + IntToStr(ErrorCode);
        ErrorCode = 0;
        Synchronize(&MyMemo1);
    }
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
    msg = myip(StrToInt(myadr));
    Synchronize(&MyMemo1);

    MySock = new TClientSocket(NULL);
    try
    {
        MySock->Address = "1.100.58.33";
        MySock->Port = 80;
        MySock->ClientType = ctBlocking;
        MySock->OnConnecting = &MySockConnecting;
        MySock->OnConnect = &MySockConnect;
        MySock->OnError = &MySockError;

        MySock->Open();

        if (MySock->Active)
        {
            //...
        }
    }
    __finally
    {
        delete MySock;
    }
}


Alternatively, you can just use the Winsock API directly:

Code: Select all
#include <winsock.h>

void __fastcall TMyThread::Execute()
{
    int err;

    msg = myip(StrToInt(myadr));
    Synchronize(&MyMemo1);

    MySock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (MySock == INVALID_SOCKET)
    {
        //...
        return;
    }

    u_long nonBlocking = 1;
    if (ioctlsocket(MySock, FIONBIO, &nonBlocking) == SOCKET_ERROR)
    {
        err = WSAGetLastError();
        //...
        closesocket(MySock);
        return;
    }

    sockaddr_in dest = {};
    dest.sin_addr.s_addr = inet_addr("1.100.58.33");
    dest.sin_port = htons(80);

    msg = "socket connecting";
    Synchronize(&MyMemo1);

    if (connect(MySock, (sockaddr*)&dest, sizeof(dest)) == SOCKET_ERROR)
    {
        err = WSAGetLastError();
        if (err != WSAEWOULDBLOCK)
        {
            //...
            closesocket(MySock);
            return;
        }

        fd_set wfd, efd;

        FD_ZERO(&wfd);
        FD_SET(MySock, &wfd);

        FD_ZERO(&efd);
        FD_SET(MySock, &efd);

        timeval timeout;
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        err = select(0, NULL, &wfd, &efd, &timeout);
        if (err <= 0)
        {
            if (err == SOCKET_ERROR)
                err = WSAGetLastError();
            else
                err = WSAETIMEDOUT;
        }
        else if (FD_ISSET(MySock, &efd))
        {
            getsockopt(MySock, SOL_SOCKET, SO_ERROR, (char*)&err, sizeof(err));
        }
        else
            err = 0;

        if (err != 0)
        {
            //...
            closesocket(MySock);
            return;
        }
    }

    msg = "socket connected";
    Synchronize(&MyMemo1);

    nonBlocking = 0;
    if (ioctlsocket(MySock, FIONBIO, &nonBlocking) == SOCKET_ERROR)
    {
        err = WSAGetLastError();
        //...
        closesocket(MySock);
        return;
    }

    //...

    closesocket(MySock);
}
Last edited by rlebeau on Tue Mar 03, 2020 12:46 pm, edited 3 times in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1665
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: OnTimer event not work

Postby mark_c » Tue Mar 03, 2020 1:33 am

thanks Remy, in the meantime you suggested another idea.
If I start with socket ctNonBlocking and make the connection and once the connection is established I use the OnConnect event to close the socket ctNonBlocking and reopen a new one with ctBlocking could it work?

Something like this:

Code: Select all
void __fastcall TMyThread::Execute()
{
   MySock = new TClientSocket(NULL);

   MySock->Address = myadr;
   MySock->Port = StrToInt(Form1->Edit1->Text);
   MySock->ClientType = ctNonBlocking;
   MySock->OnConnect = &MySocketConnect;
   MySock->OnError = &MySocketError;
   
   MySock->Open();
}
//---------------------------------------------------------------------------

void __fastcall TMyThread::MySocketConnect(TObject *Sender,
TCustomWinSocket *Socket)
{
   MySock->Close();
   
   MySock = new TClientSocket(NULL);

   MySock->Address = myadr;
   MySock->Port = StrToInt(Form1->Edit1->Text);
   MySock->ClientType = ctBlocking;
   MySock->OnError = &MySocketError;
   
   MySock->Open();   

   char Buf[1024];

   do
   {
      int ByteReceived = MySock->Socket->ReceiveBuf(Buf, sizeof(Buf));

      // .......
      // .......

   while(true);

   MySock->Close();
}



which then, something that is not clear to me: when the OnConnect event is generated it means that the Three-Way Hand Shake was successful and the connection was made correctly right?
Sometimes it seems to me that even after the OnConnect event the connection does not actually work, as if there was no connection, but maybe for other types of problems that I ignore (slowness of the server for example).
mark_c
BCBJ Master
BCBJ Master
 
Posts: 223
Joined: Thu Jun 21, 2012 1:13 am

Next

Return to Technical

Who is online

Users browsing this forum: Google [Bot] and 14 guests

cron