quit.. I mean if the client close is connection.. like closing the telnet ,
or a tcp client. If the client send a "quit|xxx[eoq]"
the server will close the client connection and everything will be fine.
look like a disconnect from a client is not reconized by the server.
2008/7/18 Survivant 00 <survivant00_at_gmail.com>:
> I found a bug.. in QuoteQueryProtocolParser
>
> if the client connect to the server.. and quit. the
> QuoteQueryProtocolParser will enter in a loop.
>
> isExpectingMoreData
> startBuffer
> capacity=8192
> hasMoreBytesToParse
> isExpectingMoreData
> releaseBuffer
> isExpectingMoreData
> startBuffer
> capacity=8192
> hasMoreBytesToParse
> isExpectingMoreData
> releaseBuffer
> isExpectingMoreData
> startBuffer
>
> I,ll try to figure out what we miss.
>
>
> 2008/7/17 John ROM <snake-john_at_gmx.de>:
>
> You take a look at source of
>> com.sun.grizzly.util.Utils.findBytes(ByteBuffer byteBuffer, byte[] b)
>>
>> byte[] b would be [eoq].getBytes()
>> >
>> >
>> >
>> > do you have an implementation in mind :)
>> >
>> > so basicaly I should convert the "[oeq]" into a byte array, and look
>> > for theses values in the BB ? (keep the index, so I don't start fromt
>> > he begining each time).
>> >
>> >
>> >
>> >
>> >
>> > 2008/7/17 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>> >
>> > Great!!!
>> >
>> >
>> >
>> > One more think it could make sense to improve in your code (IMHO) - it's
>> > place, where you try to decode ByteBuffer to CharBuffer, then check the
>> > string for [eoq]... This operation could be expensive and not optimal.
>> >
>> > Just, as idea, you can try to find [eoq] in the ByteBuffer directly and
>> > make ByteBuffer -> CharBuffer conversion only if [eoq] was found.
>> >
>> > If you didn't find [eoq] in the current ByteBuffer - you can save
>> > current position and when next portion of data will come - start to
>> > search for [eoq] not from beginning but from last position.
>> >
>> >
>> >
>> > But these are just possible ways of optimization :)
>> >
>> >
>> >
>> > Thanks.
>> >
>> >
>> >
>> > WBR,
>> >
>> > Alexey.
>> >
>> >
>> >
>> > On Jul 17, 2008, at 14:23 , Survivant 00 wrote:
>> >
>> >
>> >
>> >
>> >
>> > thanks for your explanation.. it helped.
>> >
>> > I did return true when the buffer is full, but I still got a exception
>> > (buffer full) (I was able to fix that by clearing the buffer).
>> >
>> >
>> > It could be done by returning true from hasNextMessage().
>> >
>> > And parser's getNextMessage() method implementation should return some
>> > Error message, so your next filter will get it and be able to parse.
>> >
>> > here the changes that I made :
>> >
>> > I check if the buffer size reach the max value, and if it's YES, I
>> > return true. and in the function getNextMessage() I return a string
>> > MAX that I will evaluate in the next filter.
>> >
>> > // Check if buffer is full
>> > if (processingBuffer.remaining() ==
>> > processingBuffer.capacity()) {
>> > // If full - reallocate
>> >
>> > // but check if the max length is attein
>> > if(processingBuffer.capacity() +
>> > processingBuffer.remaining()<LIMITBB){
>> > ByteBuffer newBB =
>> > ByteBufferFactory.allocateView(
>> > processingBuffer.capacity() * 2,
>> > processingBuffer.isDirect());
>> > newBB.put(processingBuffer);
>> > processingBuffer = newBB;
>> > WorkerThread workerThread = (WorkerThread)
>> > Thread.currentThread();
>> > workerThread.setByteBuffer(processingBuffer);
>> > } else {
>> > System.out.println("BUFFER MAX ATTEIND.. LE
>> > CLIENT ENVOYE DE LA JUNK OU LE BUFFER EST TROP PETIT!");
>> >
>> > processingBuffer.clear();
>> >
>> > maxBufferReached = true;
>> >
>> > return maxBufferReached;
>> > }
>> > }
>> >
>> >
>> >
>> > public String getNextMessage() {
>> > //System.out.println("getNextMessage");
>> > if(maxBufferReached){
>> > return "MAX";
>> > }
>> > return query;
>> > }
>> >
>> >
>> > in the next filter in the excute(...) I add that
>> >
>> >
>> > public boolean execute(Context context) throws IOException {
>> > String query = (String)
>> > context.removeAttribute(ProtocolParser.MESSAGE);
>> >
>> > if(query==null || query.trim().length()==0){
>> > return false;
>> > }
>> >
>> > System.out.println("query = " + query);
>> >
>> > if(query.equals("MAX")){
>> > clientConnectionHandler.close(); // close the connection
>> > because the client issending junk
>> > return false;
>> > }
>> >
>> >
>> >
>> > now I think I have a more complete example that's actually works.
>> >
>> >
>> >
>> > 2008/7/17 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>> >
>> > Hi,
>> >
>> >
>> >
>> > On Jul 16, 2008, at 21:14 , Survivant 00 wrote:
>> >
>> >
>> >
>> >
>> >
>> > just one more question.
>> >
>> > suppose this case.
>> >
>> > a client go rampage.. it send invalid data for X reason..
>> >
>> > with the actual code, when the capacity is reach, it will create a new
>> > buffer (2x size), but I want to aloid a max size.. like 20 000. the
>> > default is 8192(somthing like that) I did a system,out of
>> > processingbuffer.capacity
>> >
>> > what is the clean way to exit the parsing loop and return a state or
>> > exception to the next filter ? The next filter should be able to detect
>> > this error and close the client connection.
>> >
>> > It could be done by returning true from hasNextMessage().
>> >
>> > And parser's getNextMessage() method implementation should return some
>> > Error message, so your next filter will get it and be able to parse.
>> >
>> >
>> >
>> >
>> >
>> > and just for my information.
>> >
>> > I tought the the buffer could be flush between the loop in the
>> > filter. That's why I put the remaining data in the buffer into the
>> > WorkerThread.
>> >
>> > With ParserProtocolFilter you don't need to care about ByteBuffer...
>> > Once isExpectingMoreData() returns true - filter will save the
>> > ByteBuffer and reuse it only with current connection next time.
>> >
>> >
>> >
>> >
>> >
>> > but I suppose it's only when we create a new buffer (like double
>> > size) right ?
>> >
>> > WorkerThread workerThread = (WorkerThread)
>> > Thread.currentThread();
>> >
>> > workerThread.setByteBuffer(processingBuffer);
>> >
>> > startBuffer() method is called first, where we associate current
>> > Thread's ByteBuffer with parser's processingBuffer...
>> >
>> > So we need this:
>> >
>> > WorkerThread workerThread = (WorkerThread)
>> > Thread.currentThread();
>> >
>> > workerThread.setByteBuffer(processingBuffer);
>> >
>> >
>> >
>> > only, when we create new ByteBuffer.
>> >
>> >
>> >
>> > Thanks.
>> >
>> >
>> >
>> > WBR,
>> >
>> > Alexey.
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> > 2008/7/16 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>> >
>> > Ok, once it works, I can describe the changes.
>> >
>> >
>> >
>> > + First of all I don't use internal buffer in the parser to store
>> > temporary data there.
>> >
>> > + Fixed parser logic... I know we don't have good tutorial on that yet,
>> > so your blog could help
>> >
>> > hasMoreBytesToParse: should return true only if one message was
>> > parsed successfully, but there is still some remaining data in the
>> > buffer.
>> >
>> > releaseBuffer(): should compact the buffer, not clear... as
>> > possibly there is some remaining. Buffer should become ready for next
>> > read operation (unflipped).
>> >
>> >
>> >
>> >
>> >
>> >
>> > do you have a good link or documentation about the code behind
>> > the ByteBufferFactory ?
>> >
>> > ByteBufferFactory is Factory class for creating ByteBuffers. It's
>> > actually wrapper on top of ByteBuffer.allocate(...)/allocateDirect()...
>> >
>> > But it also implements ByteBuffer views functionality. It means
>> > ByteBufferFactory preallocates very big ByteBuffer(4M) and then, when
>> > ByteBufferFactory.allocateView(...) is called - it basically doesn't
>> > allocate new buffer, but just cuts the chunk of big preallocated buffer
>> > and returns this chunk.
>> >
>> >
>> >
>> > Seems that's it.
>> >
>> >
>> >
>> > Thanks.
>> >
>> >
>> >
>> > WBR,
>> >
>> > Alexey.
>> >
>> >
>> >
>> > I want to know what it's done under the hood, suppose that I
>> > want to do it in a project that doesn't use grizzly.. could be usefull
>> > to understand that.
>> >
>> > and thanks again for your help.
>> >
>> > now I'm almost ready to blog all about this.
>> >
>> >
>> >
>> > 2008/7/16 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>> >
>> > Pls. try attached version.
>> >
>> >
>> >
>> > WBR,
>> >
>> > Alexey.
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> > On Jul 16, 2008, at 15:45 , Survivant 00 wrote:
>> >
>> >
>> >
>> >
>> >
>> > I got a exception when I send the second request
>> >
>> > it's really simple to reproduce
>> >
>> > start the main class
>> >
>> > GrizzlyGateway
>> >
>> > it will listen on the port 5000
>> >
>> >
>> > open a telnet localhost 5000
>> >
>> > in the console.. send theses 2 requests.. One by one
>> >
>> > feed|aaa[eoq]
>> > feed|bbb[eoq]
>> >
>> >
>> > you will see that in the server console
>> >
>> >
>> > GrizzlyGateway started
>> > Simulate a disconnection from the 3th party
>> > Reconnecting...
>> > listening for incomming TCP Connections on port : 5000
>> > query = feed|aaa
>> > SENDING FEED TO CLIENT = [SYMBOL=[aaa] BID = 31.46111239671892|
>> > ASK = 41.85483961272104]
>> > SENDING FEED TO CLIENT = [SYMBOL=[aaa] BID = 19.410604221055426|
>> > ASK = 40.98782811588009]
>> > 2008-07-16 09:41:07 com.sun.grizzly.DefaultProtocolChain
>> > executeProtocolFilter
>> > GRAVE: ProtocolChain exception
>> > java.lang.IllegalStateException: ByteBuffer is full:
>> > java.nio.HeapByteBuffer[pos=0 lim=0 cap=8192]
>> > at
>> > com.sun.grizzly.filter.ReadFilter.execute(ReadFilter.java:120)
>> > at
>> > com.sun.grizzly.filter.ReadFilter.execute(ReadFilter.java:95)
>> > at
>> > com.sun.grizzly.filter.ParserProtocolFilter.execute(ParserProtocolFilter
>> > .java:108)
>> > at
>> > com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtoc
>> > olChain.java:137)
>> > at
>> > com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:1
>> > 04)
>> > at
>> > com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:9
>> > 0)
>> > at
>> > com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask
>> > .java:67)
>> > at
>> > com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.jav
>> > a:56)
>> > at
>> > com.sun.grizzly.util.WorkerThreadImpl.run(WorkerThreadImpl.java:169)
>> > SENDING FEED TO CLIENT = [SYMBOL=[aaa] BID = 10.932414591862527|
>> > ASK = 25.136572649558214]
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> > 2008/7/16 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>> >
>> > Hi,
>> >
>> >
>> >
>> > I made some changes to the parser code - please try it.
>> >
>> > The idea is to not use internal bytebuffer in the parser, but
>> > reuse one from WorkerThread...
>> >
>> > Let me know if it works, if not - please provide some unit test,
>> > using which I can test the parser myself.
>> >
>> >
>> >
>> > Thank you.
>> >
>> >
>> >
>> > WBR,
>> >
>> > Alexey.
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> > <nio_quotestock_demo_v3.zip>--------------------------------------------
>> > -------------------------
>> > To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>> > For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>>
>> --
>> Psssst! Schon vom neuen GMX MultiMessenger gehört?
>> Der kann`s mit allen: http://www.gmx.net/de/go/multimessenger
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>
>>
>