users@grizzly.java.net

Re: WG: Re: Should I use Context to store the clients references ?

From: Survivant 00 <survivant00_at_gmail.com>
Date: Mon, 21 Jul 2008 08:25:58 -0400

here the usecase.

start the server.
a client do a telnet
close the client telnet

the server will loop.

here the ouput

GrizzlyGateway started
Simulate a disconnection from the 3th party
Reconnecting...
listening for incomming TCP Connections on port : 5000
isExpectingMoreData
startBuffer
hasMoreBytesToParse
isExpectingMoreData
releaseBuffer
isExpectingMoreData
startBuffer
hasMoreBytesToParse
isExpectingMoreData
releaseBuffer
isExpectingMoreData
startBuffer
hasMoreBytesToParse
isExpectingMoreData
releaseBuffer
isExpectingMoreData
startBuffer





2008/7/21 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:

> Hi,
>
> 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.
>
> Not sure I understand how exactly server should recognize this? :) You need
> some API to be called, when client closes the connection... or?
>
>
>
>
> 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.
>>
> can you pls. provide details on where the loop will occur?
>
> Thanks.
>
> WBR,
> Alexey.
>
>
>>
>> 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
>>>
>>>
>>
>
>