Author | Topic: IDSC on SOCKETFDSETNEW | |
---|---|---|
Jose Adriano Baltieri | IDSC on SOCKETFDSETNEW on Sat, 05 Feb 2005 10:19:42 -0200 I'm having some IDSC occuring on SOCKETFDSETNEW. I cant isolate it cause the real application is too complex. Have tried but, at the prototype the error wont occur. And the prototype is too complex already. What's the real application ? I open a TELNET client socket on a thread and create at the same time a descriptor set. Because later I'll use SOCKETSELECT to "sense" if I have data waiting at this socket (are there incoming messages ?). Below I have a simplified scheme of the operations I'm doing. Just would like that someone else may have a look and point if the order of operations is wrong, or if I'm doing something risky or mistakenly. Be aware that these operations are performed on a thread. Also, connection and disconnection are protected by a "critical section" or, a SYNC METHOD. I tried this bottleneck to see if I could solve the problem but it didnt. My hypothesis is that it wouldnt be a good idea to have two or more threads connecting or disconnecting at the same time. As for the communication itself I cant bottleneck it of course cause it would be horrible. So, open/close of a socket on a single pass. One at a time. Communication happens N at a time. Follows the operations : On socket opening, I do this : SOCKETNEW(AF_INET,SOCK_STREAM,IPPROTO_TCP) SOCKETCONNECT(LNSOCKET,AF_INET,LCIP,23) SOCKETSETBLOCKINGMODE(LNSOCKET,FALSE) SOCKETFDSETNEW(@LNERROR) here comes the IDSC. Always happens here SOCKETFD_SET(LNSOCKET,LNDS) Then I add an array like this {LNSOCKET,LNDS} to a PUBLIC array. As a matter of fact, this PUBLIC array is an array of terminals that my application holds on. The application is called TELNET CONNECTION KEEPER and, this array is the "KEEPER" itself. Several threads will operate with lines of this array. So, one thread searches this array for a terminal and does communication through it. Other thread may catch the same terminal later, but not simultaneously, of course. For each terminal I have a thread ? No. I may have say 30 terminals opened and only 10 threads for instance. A thread receives a web transaction from a user and will communicate using that user's terminal (which is on that array). After sending result back to the browser, this thread will end it's job and await for another transaction, from other user, other terminal. During communication, which I call XMIT/RECEIVE I do this : SOCKETSEND REPEAT SOCKETRECV(...MSG_NORMAL) SOCKETSELECT IF SOCKETSELECT returns 0 then IF NOT SOCKETFD_ISSET(mysocket) SOCKETFD_SET(mysocket) END IF END IF I dont know why but sometimes the socket is lost from the descriptor set, then I have to add it again... I guess that when I have a timeout the socket falls out of the descriptor UNTIL I HAVE special ending character (ETX) at the end of the message On closing : SOCKETFD_ZERO SOCKETFDSETDELETE SOCKETSHUTDOWN SOCKETCLOSE So, after all, is this order of operations OK ? Something risky ? Something I could do to have a better diagnosis of what's wrong ? Something to prevent the IDSC or at least to survive after it ? A way to simplify things ? thanXs for your suPPort ! | |
Phil Ide | Re: IDSC on SOCKETFDSETNEW on Mon, 07 Feb 2005 11:08:31 +0000 Adriano, > I'm having some IDSC occuring on SOCKETFDSETNEW. I'm not sure why you are setting a socket-set. This is only required in functionally challenged environments such as VB which are single-threaded, and there a single test will determine whether this is incoming data on any of a given set of sockets. In a multi-threaded environment, where each socket is handled in it's own thread, simply ..recv() the data. If the socket is blocking, this will pause the thread until either data is received or the socket is closed. In a non-blocking socket, it will return immediately either with data (if any was pending) or without. Alternatively, you can make the socket event driven, so when data arrives at the socket, a function is automatically called to process the data. The only reason you should want to handle a socket-set that I can see, is when you have to monitor multiple sockets in a single thread. Regards, Phil Ide *************************************** * Xbase++ FAQ, Libraries and Sources: * * goto: http://www.idep.org.uk/xbase * *************************************** Do not pay any attention to this. | |
Jose Adriano Baltieri | Re: IDSC on SOCKETFDSETNEW on Mon, 07 Feb 2005 09:21:53 -0200 Phil Ide wrote: > Adriano, Hi Phil ! What a coincidence. It's Carnival here in Brazil but I'm working. I came "dry and thirsty" to see if there was an answer and there was none... Then, WHILE I was doing some other postings, you replied. I guess I should make some cards on Lottery with 09:08 ! > > >>I'm having some IDSC occuring on SOCKETFDSETNEW. > > > I'm not sure why you are setting a socket-set. This is only required in > functionally challenged environments such as VB which are single-threaded, > and there a single test will determine whether this is incoming data on any > of a given set of sockets. > > In a multi-threaded environment, where each socket is handled in it's own > thread, simply ..recv() the data. If the socket is blocking, this will > pause the thread until either data is received or the socket is closed. I wanna have a timeout procedure. > > In a non-blocking socket, it will return immediately either with data (if > any was pending) or without. > > Alternatively, you can make the socket event driven, so when data arrives > at the socket, a function is automatically called to process the data. That would be better, more stethical. Don't know how to do that, however. How to hook a code block to a TCP/SIP event ? > The only reason you should want to handle a socket-set that I can see, is > when you have to monitor multiple sockets in a single thread. Don't do that. Each thread has only one socket.... Basically, what I need is this : EMIT data through the socket AWAIT until there is data The "AWAIT" has some requirements : - I don't want to consume CPU for that or, I want to use the minimum CPU. - Need to have a maximum timeout, which is 90 seconds nowadays. - I consider that data is ready to be grabbed when there is a special set of characters in it. They are iac + eor (CHR(255) + CHR(239)). So, could I do the same without using Socket Descriptors ? > Regards, | |
Phil Ide | Re: IDSC on SOCKETFDSETNEW on Mon, 07 Feb 2005 13:50:50 +0000 Adriano, > I wanna have a timeout procedure. Then you should look at a better way to do it. Using event-driven sockets allows your thread to monitor idle-time. For example: nEvent := AppEvent( @mp1, @mp2, @oXbp, nTimeout ) This will receive an FD_READ event when data is pending, FD_CLOSE when the client attempts to close the connection, and the event-wait will timeout after nTimeout expires. Note that even though your event-handler has timed-out, the socket hasn't. If you want to close the socket now, you'll have to issue a SocketClose() on the socket. NOte that this will cause an event to be fed into the event queue, so you should re-enter the wait-state to process it. The other way to do it, is to set a timeout on the socket itself. Using Xb2.NET this is simplicity itself, and also allows you to set different timeouts for send and receive. You can also do the same with ASINET, but need to call a WinAPI routine (SetSocketOpt()) to do this. >> Alternatively, you can make the socket event driven, so when data arrives >> at the socket, a function is automatically called to process the data. > > That would be better, more stethical. Don't know how to do that, however. > > How to hook a code block to a TCP/SIP event ? You don't do it like that. You create a window using the WinAPI and in the windows WinProc you watch out for an XbeP_User event. When the XbeP_User event you have specified occurs, you use _conCall() to invoke your favourite Xbase++ function to handle the event. Once the window has been created, set the socket to send events to the event queue using WSAAsyncSelect(). For an existing application, this is a non-trivial excercise because not only do you have to change your code path for client-oriented sockets, you also have to change it for your listening socket (making the listening socket event driven is good because all subsequent client-sockets generated inherit the even-driven configuration). > Basically, what I need is this : > > EMIT data through the socket > AWAIT until there is data > > The "AWAIT" has some requirements : > > - I don't want to consume CPU for that or, I want to use the minimum CPU. > - Need to have a maximum timeout, which is 90 seconds nowadays. > - I consider that data is ready to be grabbed when there is a special set of > characters in it. They are iac + eor (CHR(255) + CHR(239)). > > > So, could I do the same without using Socket Descriptors ? Yes. When in ..recv() or ..send() call, no CPU time is consumed until data arrives or while actually sending. See above for 2 techniques. Additionally, you could spawn another thread to monitor other threads handling client-connections. This thread should maintain an array of socket descriptors and a time when they should timeout, and periodically scan the array to see if a socket has time out. If it finds one, simply close the socket and remove the data from the array. Each time the cleint-thread enters a ..recv() call, update the timeout. On exit from a ..recv() call, set the next timout to something that will not cause the monitor thread to timeout the socket before you re-enter the ..recv() call. When you close the socket for any reason other than a timeout, remember to remove the socket from the monitor thread! You should NEVER wait for specific characters in the input stream. There is a possibility that the input buffer of the ..recv() function is not large enough to hold sufficient data to make these characters visible. Even if the input buffer is large enough, there is no guarantee that the sending client's send buffer is large enough to transmit that data (requiring you to empty the buffer in order to let the client write more). Whenever you see data on the socket - fetch it! You may need to buffer retrieved data to build a complete message, but don't leave data in a socket longer than you have to. Regards, Phil Ide *************************************** * Xbase++ FAQ, Libraries and Sources: * * goto: http://www.idep.org.uk/xbase * *************************************** As I said before, I never repeat myself. | |
Jose Adriano Baltieri | Re: IDSC on SOCKETFDSETNEW on Wed, 09 Feb 2005 16:39:55 -0200 Phil Ide wrote: > nEvent := AppEvent( @mp1, @mp2, @oXbp, nTimeout ) > > This will receive an FD_READ event when data is pending, FD_CLOSE when the > client attempts to close the connection, and the event-wait will timeout > after nTimeout expires. This is nice but I would have to change my whole application... Cant do that right now.... > The other way to do it, is to set a timeout on the socket itself. Using > Xb2.NET this is simplicity itself, and also allows you to set different > timeouts for send and receive. You can also do the same with ASINET, but > need to call a WinAPI routine (SetSocketOpt()) to do this. XB2.NET - I would have to buy it. Also cant afford... SetSocketOption, from ASINET itself, doesnt seem to have anything related to timeout Would I be able to DLLCALL something in order to set what you said ? This alternative, to have a timeout for the socket itself, that is, inside the socket itself, would be the best cause it wont disturb my application so much. Thanks again ! | |
Phil Ide | Re: IDSC on SOCKETFDSETNEW on Thu, 10 Feb 2005 10:30:41 +0000 Adriano, >> nEvent := AppEvent( @mp1, @mp2, @oXbp, nTimeout ) >> >> This will receive an FD_READ event when data is pending, FD_CLOSE when the >> client attempts to close the connection, and the event-wait will timeout >> after nTimeout expires. > > This is nice but I would have to change my whole application... > Cant do that right now.... That's the thing with event-driven sockets - it's not a simple change, it completely changes the architecture of your application, so needs to be done at the start. Regards, Phil Ide *************************************** * Xbase++ FAQ, Libraries and Sources: * * goto: http://www.idep.org.uk/xbase * *************************************** Hell hath no pizza | |
Jose Adriano Baltieri | Re: IDSC on SOCKETFDSETNEW on Wed, 09 Feb 2005 16:47:52 -0200 Phil Ide wrote: > Adriano, > > > The other way to do it, is to set a timeout on the socket itself. Using > Xb2.NET this is simplicity itself, and also allows you to set different > timeouts for send and receive. You can also do the same with ASINET, but > need to call a WinAPI routine (SetSocketOpt()) to do this. Of course I'd prefer to use ASINET itself for specifying this TIMEOUT for receiving data from a socket. At the docs, there isn't such parameter. However, at the Asinetc.ch, on line #101, there's a define for that : #define SO_RCVTIMEO 0x1006 /* receive timeout */ Would it be a problem of no documentation or shouldn't these DEFINEs be used ? Or should they be used internally, only ? | |
Phil Ide | Re: IDSC on SOCKETFDSETNEW on Thu, 10 Feb 2005 10:29:05 +0000 Adriano, > Of course I'd prefer to use ASINET itself for specifying this TIMEOUT for > receiving data from a socket. > > At the docs, there isn't such parameter. > > However, at the Asinetc.ch, on line #101, there's a define for that : > > #define SO_RCVTIMEO 0x1006 /* receive timeout */ > > Would it be a problem of no documentation or shouldn't these DEFINEs be used ? > > Or should they be used internally, only ? It will probably work, provided you call the function correctly. If I get a chance, I'll investigate this later today (but no promises, I have a busy day ahead). Regards, Phil Ide *************************************** * Xbase++ FAQ, Libraries and Sources: * * goto: http://www.idep.org.uk/xbase * *************************************** Call your Father today: I wish I still COULD! | |
Jose Adriano Baltieri | Re: IDSC on SOCKETFDSETNEW on Thu, 10 Feb 2005 08:49:43 -0200 Phil Ide wrote: > Adriano, > > >>Of course I'd prefer to use ASINET itself for specifying this TIMEOUT for >>receiving data from a socket. >> >>At the docs, there isn't such parameter. >> >>However, at the Asinetc.ch, on line #101, there's a define for that : >> >>#define SO_RCVTIMEO 0x1006 /* receive timeout */ >> >>Would it be a problem of no documentation or shouldn't these DEFINEs be used ? >> >>Or should they be used internally, only ? > > > It will probably work, provided you call the function correctly. If I get > a chance, I'll investigate this later today (but no promises, I have a busy > day ahead). Thank you ! I thought about asking Alaska what the DEFINEs are there for. Would it simply be a "Berkeley Save As" issue or they are just hidden at the documentation. Someone forgot to mention them. If I have the time today, I'm also curious to write a test. See ya. > > Regards, | |
Phil Ide | Re: IDSC on SOCKETFDSETNEW on Thu, 10 Feb 2005 12:42:01 +0000 Adriano, >> It will probably work, provided you call the function correctly. If I get >> a chance, I'll investigate this later today (but no promises, I have a busy >> day ahead). > > Thank you ! > > I thought about asking Alaska what the DEFINEs are there for. > Would it simply be a "Berkeley Save As" issue or they are just hidden at the > documentation. Someone forgot to mention them. > > If I have the time today, I'm also curious to write a test. There are three main reasons why something is in Xbase++ but undocumented: 1. The feature was added, but not fully tested or known to be flaky 2. The feature was added for a particular use, used internally, and not guaranteed to work in other circumstances. 3. The feature is intended only for internal use, and Alaska reserve the right to change it's name, location (library), API or even remove it altogether (::noIvarCallBack() and ::noMethodCallback() are prime examples). Additionally, something might simply have been 'forgotten' when the documentation was updated, but I really wouldn't count on this Regards, Phil Ide *************************************** * Xbase++ FAQ, Libraries and Sources: * * goto: http://www.idep.org.uk/xbase * *************************************** Fanatic: can't change his mind, won't change the subject. |