• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1045
  • Last Modified:

TCustomWinSocket Send Error Problems

I've got a multithreaded Borland Builder C++ service application that normally runs on a NT 4 Server that has major problems when one of the sockets encounters a send error. The application uses a TServerSocket (Non-Blocking) as a listening socket that spawns TCustomWinSockets (also Non-Blocking) and processing threads upon connection (multiple connections from various clients possible). The threads are TThreads and are spawned and shutdown manually rather than with the TServerSocket component. All socket communication is currently handled within the main application thread and the data is buffered to the processing threads and safteyed using critical sections (there is no VCL component access from within the threads). All works well until one of the TCustomWinSockets encounters a Send error (ErrorEvent == eeSend / 10053).  The socket disconnects as advertised and sets the Disconnect error and event and then it seems that all of the open TCustomWinSockets remain open but they appear to stop sending and receiving (or at least they don't trigger the events) and further connections are not possible although the listening socket is still active.  The application doesn't lock up nor do the threads however, the service won't stop and the entire server must be rebooted before the application will run again.  No Exceptions are noted in the logs however I do trap the socket error exception and attempt to deal with it (obviously not very well in this case :). Try/Catch on the Socket->SendText or Socket->Sendbuf do not display any triggered exceptions. This does not happen on Disconnect errors and I haven't encountered any of the other socket error types to know whether they cause the same problem or not. I'd like to keep the sockets async and have tried both Socket->SendText and Socket->Sendbuff with some monitoring.  I've also tried placing the socket read/write routines inside of TThreads and using Synchronize with no success - same problem exists. Is there some type of cleanup on the TCustomWinSocket component or socket itself that needs to be performed when a send error is recieved?  A lot (tons) more details available if needed. Any help or ideas appreciated.

Thanks,
Greg
0
gament
Asked:
gament
1 Solution
 
toschCommented:
> The application uses a TServerSocket (Non-Blocking) as a listening socket that spawns TCustomWinSockets (also Non-Blocking) and processing threads upon connection (multiple connections from various clients possible).

multiple connections from various clients can also be achieved using the ThreadBlocking mode. is this the reaseon for you to use non blocking io ?

non blocking io is harder to deal with - more error prone, less efficient and not required to allow concurrent client connections.
you should not use it unless it is really needed.

what you are doing sounds very complicated to me.

if you use the ThreadBlocking mode you still have to manually spawn the thread, but there is a special thread class called TServerClientThread whose instances can be cached by the TServerSocket component (there is the property KeepInCache to enable/disable caching).
you'll have to create this in the OnGetThread event.

i won't go into further detail because the online help is quite good about that.
if you want i can mail you a source of a simple server capable of handling multiple clients at once.
0
 
gamentAuthor Commented:
Thanks Tosch.  Actually I had originally used ThreadBlocking and had some problems with the events and changed it to async.  I'll be the first to admit though that I probably didn't spend the time needed to dig into it.  This comment in the help scared me off since I didn't have the time to mess with it -- I went async instead:

Applications that receive frequent client requests will want to derive a descendant class from TServerClientThread to handle reading and writing to separate clients. This is because TServerClientThread objects use the OnClientRead and OnClientWrite events of the associated server socket. These events are not thread-local.

I would appreciate the email with the sample you mentioned.  greg@amentfamily.net -- thanks :)

I did come to another conclusion this morning with this problem - it almost appears that the send error is generated because the socket was closed when the data was sent.  This could only happen if winsock closes the socket and I send the data before the component is updated to show the disconnect because I check for Socket->Connected just prior to sending..

Tnx,
Greg
0
 
gamentAuthor Commented:
Thanks Tosch.  Actually I had originally used ThreadBlocking and had some problems with the events and changed it to async.  I'll be the first to admit though that I probably didn't spend the time needed to dig into it.  This comment in the help scared me off since I didn't have the time to mess with it -- I went async instead:

Applications that receive frequent client requests will want to derive a descendant class from TServerClientThread to handle reading and writing to separate clients. This is because TServerClientThread objects use the OnClientRead and OnClientWrite events of the associated server socket. These events are not thread-local.

I would appreciate the email with the sample you mentioned.  greg@amentfamily.net -- thanks :)

I did come to another conclusion this morning with this problem - it almost appears that the send error is generated because the socket was closed when the data was sent.  This could only happen if winsock closes the socket and I send the data before the component is updated to show the disconnect because I check for Socket->Connected just prior to sending..

Tnx,
Greg
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
toschCommented:
> I would appreciate the email with the sample you mentioned.  greg@amentfamily.net -- thanks :)

well, i'll just post the significant code:

set the server socket component to ThreadBlocking mode and the OnGetThread event to the handler.

then you should be able to use

C:> telnet <ip> <port>

on several dos promts.

as soon you press "a" for example the output will be: "you said: a" and this one client will be hung up.


//---------------------------------------------------------------------------
#define SOCKET_STREAM_TIMEOUT 60000

class PACKAGE TTestServerThread : public TServerClientThread
{
public:
   __fastcall TTestServerThread(TServerClientWinSocket *ClientSocket);
   void __fastcall ClientExecute(void);
private:
   volatile int cnt;
};

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

__fastcall TTestServerThread::TTestServerThread
   (TServerClientWinSocket *ClientSocket)
   : TServerClientThread(false,ClientSocket)
{
   KeepInCache = true;
   FreeOnTerminate = false;
}
//---------------------------------------------------------------------------
void __fastcall TTestServerThread::ClientExecute()
{
   Form1->Memo2->
      Lines->Add("client thread spawned " + IntToStr(cnt++) + "th time");
   if (Terminated || ! ClientSocket->Connected) return;

   std::auto_ptr<TWinSocketStream> pStream
       (new TWinSocketStream(ClientSocket, SOCKET_STREAM_TIMEOUT));
   if (! pStream->WaitForData(SOCKET_STREAM_TIMEOUT)) return;

   Form1->Memo2->Lines->Add("incoming data detected");

   // read up to 256 bytes as an example request
   char buffer[256];
   int bytes = pStream->Read(buffer,sizeof(buffer));
   
   Form1->Memo2->Lines->Add("request read");

   // write a sample response
   pStream->Write("you said: ",10);
   pStream->Write(buffer,bytes);

   Form1->Memo2->Lines->Add("response written");

   // hang up the client
   ClientSocket->Close();

   Form1->Memo2->Lines->Add("end of client thread");
}

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

void __fastcall TForm1::ServerSocket1GetThread(TObject *Sender,
      TServerClientWinSocket *ClientSocket,
      TServerClientThread *&SocketThread)
{
   SocketThread = new TTestServerThread(ClientSocket);
}

//---------------------------------------------------------------------------
0
 
udilCommented:
This question has been abandoned. I will make a recommendation to the moderators on its resolution in a week or two. I appreciate any comments that would help me to make a recommendation.

In the absence of responses, I may recommend DELETE unless it is clear to me that it has value as a PAQ. Silence = you don't care

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Udil
EE Cleanup Volunteer
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Grade B to tosch

Please leave any comments here within the next seven days.
 
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Ged
EE Cleanup Volunteer

0
 
toschCommented:
My program I cut the posted code from is working well with several clients.
I am really interested if it was of any help, though.
0

Featured Post

Become an Android App Developer

Ready to kick start your career in 2018? Learn how to build an Android app in January’s Course of the Month and open the door to new opportunities.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now