custom socket set OnError event

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

custom socket set OnError event

Postby mark_c » Mon Jan 27, 2020 6:57 am

how do I implement the OnError event for a custom socket?

thank you

Code: Select all
void __fastcall TMyThread::Execute()
{
   TClientSocket *MySock;

   MySock = new TClientSocket(NULL);

   MySock->Address = myadr;
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;

   MySock->OnError = ????????;

   MySock->Open();


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


   if(MySock->Active) MySock->Close();
}
 
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: custom socket set OnError event

Postby mark_c » Tue Jan 28, 2020 1:51 am

sorry but I solved it

Only doubt that remains for me is the following: if i instantiate n threads, do i also have to synchronize access to events?

Code: Select all
void __fastcall TMyThread::Execute()
{
   TClientSocket *MySock;

   MySock = new TClientSocket(NULL);

   MySock->Address = myadr;
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;

   MySock->OnError = &Form1->MySocketError;

   MySock->Open();


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

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

//---------------------------------------------------------------------------
void __fastcall TForm1::MySocketError(TObject *Sender,
     TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
      ErrorCode=0;
      Socket->Close();
}
//---------------------------------------------------------------------------
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: custom socket set OnError event

Postby mark_c » Tue Jan 28, 2020 2:13 pm

this is a version where I try to extend the TClientSocket class but it doesn't compile and I don't understand why.
The reason is that I want to implement the events unlinked from the Form but I don't know if it is the correct way.
Code: Select all
class MyTestClass : public TClientSocket
{
private:
protected:
public:
   __fastcall MyTestClass();
   void __fastcall MySocketError(TObject *Sender,
   TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode);
};

void __fastcall TMyThread::Execute()
{
   MyTestClass *MySock;

   MySock = new MyTestClass(NULL);

   MySock->Address = myadr;
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;

   MySock->OnError = &MySocketError;

   MySock->Open();


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

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

//---------------------------------------------------------------------------
void __fastcall MyTestClass::MySocketError(TObject *Sender,
TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
   ErrorCode=0;
}
//---------------------------------------------------------------------------
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: custom socket set OnError event

Postby rlebeau » Tue Jan 28, 2020 2:19 pm

mark_c wrote:how do I implement the OnError event for a custom socket?


You really don't need to use the OnError event in ctBlocking mode. After the OnError handler is called, fatal socket errors will raise an ESocketError exception that you can catch in a try..catch block, eg:

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

   MySock->Address = myadr;
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;

   try
   {
      MySock->Open();
      try {
         ...
      }
      __finally {
         MySock->Close();
      }
   }
   catch (const Exception &e)
   {
      ...
   }

   delete MyTestClass;
}


That being said, if you really want to use the OnError event, you will have to assign a handler to it manually, eg:

Code: Select all
void __fastcall TMyThread::SocketError(TObject *Sender, TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
   ...
}

void __fastcall TMyThread::Execute()
{
   TClientSocket *MySock = new TClientSocket(NULL);
   ...
   MySock->OnError = &SocketError;
   ...
}


mark_c wrote:Only doubt that remains for me is the following: if i instantiate n threads, do i also have to synchronize access to events?


Not to the events themselves, as they will be called in the context of their respective threads. But, if they access shared resources, like the UI, then yes, you need to synchronize those operations.

mark_c wrote:this is a version where I try to extend the TClientSocket class but it doesn't compile and I don't understand why.


Because you are not referring to MySocketError() correctly when trying to assign it to the OnError event. You are telling the compiler to look for it in the TMyThread class, where it does not exist. You need to tell the compiler to look for it in the MyTestClass object instead:

Code: Select all
void __fastcall TMyThread::Execute()
{
   MyTestClass *MySock = new MyTestClass(NULL);
   ...
   MySock->OnError = &MySock->MySocketError;
   ...
}


But, that said, if you want to handle errors inside the Socket class itself, then the CORRECT way is to override the virtual Error() method instead:

Code: Select all
class MyTestClass : public TClientSocket
{
private:
protected:
   void __fastcall Error(TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode);
public:
   __fastcall MyTestClass();
};

void __fastcall MyTestClass::Error(TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
   ...
   // call the following to fire the OnError event handler, if needed...
   TClientSocket::Error(Socket, ErrorEvent, ErrorCode);
}
Last edited by rlebeau on Tue Jan 28, 2020 2:33 pm, edited 5 times in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1649
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: custom socket set OnError event

Postby mark_c » Tue Jan 28, 2020 2:25 pm

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

Re: custom socket set OnError event

Postby mark_c » Wed Jan 29, 2020 4:57 am

thanks Remy.
Another thing I didn't understand: if I create a class that is similar to the one you showed me, and I instantiate n threads, do I finally have a private OnRead event for each thread?

Code: Select all
class TMyThread : public TThread
{
private:

protected:
   void __fastcall Execute();
   void __fastcall SocketError(TObject *Sender, TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode);
   void __fastcall SocketRead(TObject *Sender, TCustomWinSocket *Socket);
public:
   __fastcall TMyThread(const AnsiString &Adr);
        void __fastcall MyMemo1();
};



if I implement this, I do not receive any data; is it because the Socket does not refer to one of my n instantiated threads but refers Socket to the main thread, the GUI thread to understand us?
Code: Select all
void __fastcall TMyThread::SocketConnecting(TObject *Sender,
      TCustomWinSocket *Socket)
{
        char *Buf = new char[100];
        msg=Socket->ReceiveBuf(Buf, 100);
        Synchronize(&MyMemo1);
}
//---------------------------------------------------------------------------


I tried to display the socket address in the thread body and the one in the event and it looks the same; but I don't know if it means something.

the results:
Code: Select all
OnConnect: 31568640
Body Thread: 31568640
OnConnect: 31568832
Body Thread: 31568832
OnConnect: 31568352
Body Thread: 31568352
OnConnect: 31568544
Body Thread: 31568544
OnConnect: 31568448
Body Thread: 31568448


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

   MySock->Address = myadr;
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;
    MySock->OnError = &SocketError;
    MySock->OnRead = &SocketRead;
    MySock->OnConnect = &SocketConnect;
   MySock->Open();

    msg="Body Thread: " + String((DWORD)MySock->Socket);
    Synchronize(&MyMemo1);
}
//---------------------------------------------------------------------------

void __fastcall TMyThread::SocketConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
// it works
        msg="OnConnecting: " + String((DWORD)Socket);
        Synchronize(&MyMemo1);
        Socket->SendText("GET /\r\n");
}
//---------------------------------------------------------------------------

void __fastcall TMyThread::SocketRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
// does not work
        msg="OnRead";
        Synchronize(&MyMemo1);
}
//---------------------------------------------------------------------------
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: custom socket set OnError event

Postby rlebeau » Wed Jan 29, 2020 1:07 pm

mark_c wrote:if I create a class that is similar to the one you showed me, and I instantiate n threads, do I finally have a private OnRead event for each thread?


Yes, each thread will have its own OnRead handler, separate from other threads.

mark_c wrote:if I implement this, I do not receive any data; is it because the Socket does not refer to one of my n instantiated threads but refers Socket to the main thread, the GUI thread to understand us?


No, not at all. You are not getting any data because the OnRead event (and, in fact, most of the TClientSocket's events) are simply NOT USED in ctBlocking mode to begin with. You must use a separate TWinSocketStream object to read from, and write to, the socket, as stated in the TClientSocket.ClientType documentation.

In ctNonBlocking mode, the OnRead event (and other events) are used, but are dependent on the calling thread having an active message loop (which your worker thread does not), as the TClientSocket will create an internal window to receive asynchronous notifications from the OS.

In ctBlocking mode, that internal window is not used. You need something more like this instead:

Code: Select all
void __fastcall TMyThread::Execute()
{
   try
   {
      TClientSocket *MySock = new TClientSocket(NULL);
      try
      {
         MySock->Address = myadr;
         MySock->Port = 80;
         MySock->ClientType = ctBlocking;

         msg = "OnConnecting";
         Synchronize(&MyMemo1);

         MySock->Open();
         try
         {
            msg = "OnConnect";
            Synchronize(&MyMemo1);

            TWinSocketStream *Strm = new TWinSocketStream(MySock->Socket, 30000);
            try
            {
               AnsiString req = "GET / HTTP/1.1\r\nHost: " + myadr + "\r\nConnection: close\r\n\r\n";
               char *ptr = req.c_str();
               int size = req.Length();
               do {
                  int numSent = Strm->Write(ptr, size);
                  if (numSent == 0)
                     throw ESocketError(SysErrorMessage(WSAETIMEDOUT));
                  ptr += numSent;
                  size -= numSent;
               }
               while (size > 0);

               if (!Strm->WaitForData(15000))
                  throw ESocketError(SysErrorMessage(WSAETIMEDOUT));

               msg = "OnRead";
               Synchronize(&MyMemo1);
            }
            __finally {
               delete Strm;
            }
         }
         __finally {
            MySock->Close();
         }
      }
      __finally {
         delete MySock;
      }
   }
   catch (const Exception &e)
   {
      msg = "OnError: " + e.Message;
      Synchronize(&MyMemo1);
   }
}


mark_c wrote:
Code: Select all
void __fastcall TMyThread::SocketConnecting(TObject *Sender,
      TCustomWinSocket *Socket)
{
        char *Buf = new char[100];
        msg=Socket->ReceiveBuf(Buf, 100);
        Synchronize(&MyMemo1);
}


FYI, that code is leaking memory. You need to delete[] the array when you are done using it:

Code: Select all
char *Buf = new char[100];
msg = Socket->ReceiveBuf(Buf, 100);
...
delete[] Buf;


Or. simply don't use new[] to begin with:

Code: Select all
char Buf[100];
msg = Socket->ReceiveBuf(Buf, 100);
...


mark_c wrote:I tried to display the socket address in the thread body and the one in the event and it looks the same; but I don't know if it means something.


All it means is that you are printing out the same TCustomWinSocket object pointer each time, as you should be, because there is only 1 TCustomWinSocket object per TClientSocket instance.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1649
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: custom socket set OnError event

Postby mark_c » Wed Jan 29, 2020 1:21 pm

thanks Remy.

because if I instantiate only 1 thread I don't lose data instead, if I instantiate 5 with different ip addresses I lose data?
With 5 threads the data is truncated.

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

   MySock->Address = myadr;
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;

   MySock->OnError = &MySocketError;
   MySock->OnDisconnect = &MySocketDisconnect;
   MySock->Open();

   AnsiString Request = "GET / HTTP/1.1\r\nHost: " + myadr + "\r\nConnection: keep-alive\r\n\r\n";
   
   char *buffer = Request.c_str();
   int buffer_len = Request.Length();

   int sent;
   do
   {
      sent = MySock->Socket->SendBuf(buffer, buffer_len);
      if (sent == -1)
      {
         MySock->Socket->Close();
         return;
      }
      buffer += sent;
      buffer_len -= sent;
   }
   while (buffer_len > 0);


   AnsiString MyBuffer;

   do
   {
      int Size = MySock->Socket->ReceiveLength();
      char *Buf = new char[Size];
      do
      {
         int ByteReceived = MySock->Socket->ReceiveBuf(Buf, Size);

         if (ByteReceived <= 0)
         break;

         MyBuffer+=AnsiString(Buf, ByteReceived);
         Size -= ByteReceived;
      }
      while( Size > 0 );

      delete []Buf;

      int Term = MyBuffer.Pos("\r\n\r\n");

      if (Term != 0)
      {
         msg = "(" + myadr + ")\r\n" + MyBuffer;
         Synchronize(&MyMemo1);
         break;
      }
   }
   while(1);

   MySock->Close();

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

Re: custom socket set OnError event

Postby rlebeau » Fri Jan 31, 2020 12:39 pm

mark_c wrote:because if I instantiate only 1 thread I don't lose data instead, if I instantiate 5 with different ip addresses I lose data? With 5 threads the data is truncated.


That means you are not handling the HTTP data correctly in general. That has nothing to do with threading, as each TClientSocket is independent of each other, especially in ctBlocking mode.

mark_c wrote:
Code: Select all
MySock->OnError = &MySocketError;
MySock->OnDisconnect = &MySocketDisconnect;


As I told you earlier, you need to stop relying on events in ctBlocking mode.

mark_c wrote:
Code: Select all
sent = MySock->Socket->SendBuf(buffer, buffer_len);


As I told you earlier, you should be using TWinSocketStream in ctBlocking mode. Did you look at the example I gave you earlier?

mark_c wrote:
Code: Select all
int Size = MySock->Socket->ReceiveLength();
char *Buf = new char[Size];


You are not checking the return value of ReceiveLength(). If it returns -1, a failure occurred, stop reading. If it returns 0, no data is available, wait some time before checking again. You can use the Winsock select() function to detect when data is available instead of polling for it. Or, using TWinSocketStream (like you are supposed to in ctBlocking mode), use its WaitForData() method. ReceiveLength() does not block waiting for data to arrive, it reports how many bytes are available at that exact moment only. It is undefined behavior to allocate a dynamic array of <= 0 size.

You are better off simply not using ReceiveLength() at all, just use a fixed-sized buffer instead. And you should just call ReceiveBuf() (or TWinSocketStream::Read()) unconditionally and let it block until data arrives.

Also, when you are calling ReceiveBuf(), if it returns <= 0, you are breaking your inner loop only, you are not breaking your outer loop, so you end up going right back to calling ReceiveLength() after ReceiveBuf() fails if your MyBuffer does not contain "\r\n\r\n" yet.

Try this:

Code: Select all
#include <memory>

void __fastcall TMyThread::Execute()
{
   std::auto_ptr<TClientSocket> MySock(new TClientSocket(NULL));
   // or std::unique_ptr in C++11 and later...

   MySock->Address = myadr;
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;

   MySock->Open();

   //std::auto_ptr<TWinSocketStream> Strm(new TWinSocketStream(MySock->Socket, 10000));

   AnsiString Request = "GET / HTTP/1.1\r\nHost: " + myadr + "\r\nConnection: close\r\n\r\n";
   
   char *buffer = Request.c_str();
   int buffer_len = Request.Length();

   int sent;
   do
   {
      //sent = Strm->Write(buffer, buffer_len);
      sent = MySock->Socket->SendBuf(buffer, buffer_len);
      if (sent == -1)
         return;

      buffer += sent;
      buffer_len -= sent;
   }
   while (buffer_len > 0);

   AnsiString MyBuffer;
   char Buf[1024];
   int ByteReceived;

   do
   {
      //ByteReceived = Strm->Read(Buf, sizeof(Buf));
      ByteReceived = MySock->Socket->ReceiveBuf(Buf, sizeof(Buf));
      if (ByteReceived < 0)
         return;

      if (ByteReceived == 0)
         break;

      MyBuffer += AnsiString(Buf, ByteReceived);

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

   msg = "(" + myadr + ")\r\n" + MyBuffer;
   Synchronize(&MyMemo1);
}


Now, that being said, is there a particular reason why you are stuck using the old and obsolete TClientSocket component to implement HTTP manually, instead of using a more modern HTTP component, like Indy's TIdHTTP? That would greatly simplify your code, eg:

Code: Select all
#include <IdHTTP.hpp>
#include <memory>

void __fastcall TMyThread::Execute()
{
   std::auto_ptr<TIdHTTP> MyHTTP(new TIdHTTP(NULL));

   MyHTTP->Get("http://" + myadr + "/", (TStream*)NULL);

   msg = "(" + myadr + ")\r\n" + MyHTTP->ResponseText + "\r\n" + MyHTTP->Response->RawHeaders->Text;
   Synchronize(&MyMemo1);
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1649
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: custom socket set OnError event

Postby mark_c » Fri Jan 31, 2020 1:34 pm

thanks Remy.
So your advice is: with blocking sockets forget about events.

Anyway, I was insisting on the old road just to understand, thanks again Remy.
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: custom socket set OnError event

Postby rlebeau » Sun Feb 02, 2020 3:03 pm

mark_c wrote:So your advice is: with blocking sockets forget about events.


Yes.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1649
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: custom socket set OnError event

Postby mark_c » Tue Feb 04, 2020 2:17 am

great Remy as always.
In this version of the code, if I introduce a certain number of attempts when ByteReceived == 0, would it make sense?
I thought that ByteReceived returns 0 if at that moment the buffer is perhaps full or the server is overloaded: could it be so?

Code: Select all
#include <memory>

void __fastcall TMyThread::Execute()
{
   std::auto_ptr<TClientSocket> MySock(new TClientSocket(NULL));
   // or std::unique_ptr in C++11 and later...

   MySock->Address = myadr;
   MySock->Port = 80;
   MySock->ClientType = ctBlocking;

   MySock->Open();

   //std::auto_ptr<TWinSocketStream> Strm(new TWinSocketStream(MySock->Socket, 10000));

   AnsiString Request = "GET / HTTP/1.1\r\nHost: " + myadr + "\r\nConnection: close\r\n\r\n";

   char *buffer = Request.c_str();
   int buffer_len = Request.Length();

   int sent;
   do
   {
      //sent = Strm->Write(buffer, buffer_len);
      sent = MySock->Socket->SendBuf(buffer, buffer_len);
      if (sent == -1)
      return;

      buffer += sent;
      buffer_len -= sent;
   }
   while (buffer_len > 0);

   AnsiString MyBuffer;
   char Buf[1024];
   int ByteReceived;

   do
   {
      //ByteReceived = Strm->Read(Buf, sizeof(Buf));
      ByteReceived = MySock->Socket->ReceiveBuf(Buf, sizeof(Buf));
      if (ByteReceived < 0)
      return;

      if (ByteReceived == 0)
      break;

      MyBuffer += AnsiString(Buf, ByteReceived);

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

   msg = "(" + myadr + ")\r\n" + MyBuffer;
   Synchronize(&MyMemo1);
}


code changes with the number of attempts

Code: Select all
int nv=0;
do
{
   nv++;
   do
   {
      //.......
      // ......
      if (ByteReceived == 0)
      {
         Sleep(5000);
         break;
      }
   }
   while(true);
}
while(nv < 10);



I forgot to tell you that I am stubbornly continuing to use BCB6 32 bit version for historical reasons, I am fond of this development environment.

After this I ask you if there is a maximum number of sockets that can be opened simultaneously of the client type in windows.

Is there also a limit to the number of instantiable threads or is it just a matter of memory in this case?
Currently without increasing the stack area, if I try to instantiate 2000 threads, an exception is generated after 1519 threads.
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: custom socket set OnError event

Postby rlebeau » Tue Feb 04, 2020 2:54 pm

mark_c wrote:In this version of the code, if I introduce a certain number of attempts when ByteReceived == 0, would it make sense?


No.

mark_c wrote:I thought that ByteReceived returns 0 if at that moment the buffer is perhaps full or the server is overloaded: could it be so?


No, that is not what it means. Where did you ever get that idea from?

When a read operation returns 0 bytes received, it means the peer gracefully closed its end of the connection. You need to stop and close your end of the connection. That is why in my earlier example, I 'break' the reading loop if the connection is closed before the HTTP header terminator ("\r\n\r\n") is reached.

mark_c wrote:code changes with the number of attempts


That change is not necessary, or correct. The ONLY condition that should ever need to do that kind of looping is when the read operation fails with a WSAEWOULDBLOCK error, but that cannot happen in blocking mode, so that loop makes no sense in this example.

mark_c wrote:I forgot to tell you that I am stubbornly continuing to use BCB6 32 bit version for historical reasons, I am fond of this development environment.


As am I. I still use BCB6 daily in my day job.

mark_c wrote:After this I ask you if there is a maximum number of sockets that can be opened simultaneously of the client type in windows.


On Windows, the number of active sockets is limited only by available memory, as sockets are treated as true kernel objects. Unlike on other platforms, where sockets use file descriptors and there is usually a limit on the number of open file descriptors.

Note that for client sockets, you can also be limited by the number of local ports that are available. It really depends on what destinations the clients are connected to. For example, if you have multiple clients connected to the same server IP/port, then you are limited to 65535 clients per network adapter, since ports are 16bit numbers, and socket connections are uniquely identified by a tuple of protocol, local IP/port, and remote IP/port, so the number of unique combinations available decreases when portions of those tuples are repeated by multiple connections.

mark_c wrote:Is there also a limit to the number of instantiable threads or is it just a matter of memory in this case?


Yes, the number of threads you can create is also limited only by available memory.

mark_c wrote:Currently without increasing the stack area, if I try to instantiate 2000 threads, an exception is generated after 1519 threads.


The default stack size is 1MB. So 2000 threads would easily reach the default 2GB limit for a 32bit process. To create more threads, you would have to decrease (not increase!) the stack size of each thread. But a 32bit process should NEVER need that many threads to begin with. That is a sign of poor code design. In this situation, using asynchronous socket I/O would come into play, either by using non-blocking sockets with multiplexing via the Winsock select() or WSAPoll() function, or using a small handful of threads with Win32 Overlapped I/O or I/O Completion Ports.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1649
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: custom socket set OnError event

Postby mark_c » Mon Feb 10, 2020 5:44 am

sorry Remy, but you already answered me here
viewtopic.php?f=10&t=3262
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am


Return to Technical

Who is online

Users browsing this forum: No registered users and 24 guests

cron