?
Solved

TCustomWinSocket Send Error Problems

Posted on 2003-02-19
7
Medium Priority
?
1,006 Views
Last Modified: 2008-02-07
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
Comment
Question by:gament
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
7 Comments
 
LVL 3

Expert Comment

by:tosch
ID: 7983685
> 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
 

Author Comment

by:gament
ID: 7986881
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
 

Author Comment

by:gament
ID: 7986887
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
Technology Partners: 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!

 
LVL 3

Accepted Solution

by:
tosch earned 300 total points
ID: 7988970
> 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
 
LVL 2

Expert Comment

by:udil
ID: 8867112
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
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 9356010
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
 
LVL 3

Expert Comment

by:tosch
ID: 9364581
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

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!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.
Suggested Courses

801 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question