It's possible that the server never received the TCP FIN packet and therefor did not know that it should close the IoSession. There are situations where a host has no way of knowing that the TCP socket has closed unless it tries to write data to the socket and that write fails. This is not a limitation of MINA. This is just the way socket I/O works.
If this is the cause of your problem, you have a couple of options. You could use some type of watch dog mechanisms that sends data at a regular interval. If the connection is no longer valid, the write will fail and the socket will get closed thereby triggering a sessionClosed event. Or you could use the MINA read idle notification. This way after a certain amount of time has passed and your server hasn't received any data for a particular IoSession, you can manually close the IoSession. If your problem still persists after implementing one of these solutions, please let us know. -Mike jhcha wrote: > Dear Mina developers. > I'm trying to use mina 1.1.5 to develop the very big stress server. > I test my server with jmeter like some echo test now. > > test environment > > * jmeter : > echo message size : 1024 bytes > jmeter threads : 100 > loop count : 1000 > sampler : TCP Sampler > reuse connection : false > > * server : HP-UX 2 cores > java HotSpot(TM) Server VM (build 1.5.0.07 jinteg:03.20.07-11:05 > IA64, mixed mode) > my server(mina) > > * client : pc (dual core). > jmeter > > when I tested the stress, I found sessionCreated called counts are a little > bigger than sessionClosed called counts. > so, I tried to find out why that mismatch occured during several days. > and I found the followings : > > > org.apache.mina.common.support.IoServiceListenerSupport > { > > public void fireSessionCreated(IoSession session) { > SocketAddress serviceAddress = session.getServiceAddress(); > > // Get the session set. > Set<IoSession> s = new IdentityHashSet<IoSession>(); > Set<IoSession> sessions = > managedSessions.putIfAbsent(serviceAddress, > Collections > .synchronizedSet(s)); > boolean firstSession; > > if (null == sessions) { > sessions = s; > firstSession = true; > } else { > firstSession = false; > } > > // If already registered, ignore. > if (!sessions.add(session)) { > return; > } > > // If the first connector session, fire a virtual service > activation > // event. > if (session.getService() instanceof IoConnector && > firstSession) { > fireServiceActivated(session.getService(), > session.getServiceAddress(), > session > .getHandler(), > session.getServiceConfig()); > } > > // Fire session events. > session.getFilterChain().fireSessionCreated(session); <-- > called > correctly > session.getFilterChain().fireSessionOpened(session); <-- > called correctly > > // Fire listener events. > for (IoServiceListener listener : listeners) { > listener.sessionCreated(session); <-- called correctly > } > } > > > public void fireSessionDestroyed(IoSession session) { > boolean lastSession = false; > SocketAddress serviceAddress = session.getServiceAddress(); > > // Get the session set. > Set<IoSession> sessions = managedSessions.get(serviceAddress); > // Ignore if unknown. > if (sessions == null) { > // logger.error("fireSessionDestroyed() : sessions == > null < " + > session); > return; <-- occured sometimes !!!!!!!!!!!!!!!!!! > } > > sessions.remove(session); > > // Try to remove the remaining empty session set after removal. > if (sessions.isEmpty()) { > lastSession = managedSessions.remove(serviceAddress, > sessions); > } > > // Fire session events. > session.getFilterChain().fireSessionClosed(session); <-- > skipped sometimes > > // Fire listener events. > try { > for (IoServiceListener listener : listeners) { > listener.sessionDestroyed(session); <-- skipped > sometimes > } > } finally { > // Fire a virtual service deactivation event for the > last session of > // the connector. > // TODO double-check that this is *STILL* the last > session. May not > // be the case > if (session.getService() instanceof IoConnector && > lastSession) { > fireServiceDeactivated(session.getService(), > session.getServiceAddress(), session > .getHandler(), > session.getServiceConfig()); <-- skipped sometimes > } > } > } > > the above fireSessionDestroyed method called as the same number as > fireSessionCreated method. > > but the mysterious event is that the sessions is not gotten from > managedSessions in fireSessionDestroyed, > i.e. SocketAddress key is not found in managedSessions. > then the remaining logic was skipped. > so fireSessionClosed, sessionDestroyed ... are not called sometimes. > > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:15059, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:15961, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:23883, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:24036, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:31341, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:31343, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:31345, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:45839, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:5317, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null < > (SOCKET, R: /172.26.73.107:8471, L: /10.88.50.205:30000, S: > 0.0.0.0/0.0.0.0:30000) > > I think the reason that the 100 client threads tries to proceed "conect, > send, receive, close", > different sessions has the same client SocketAddress at times in server, > and the origin of that problem is client's stress environment. > > It is possible the following senario : > > I/O processor thread I/O processor thread client thread client > thread > one two one two > -------------------------------------------------------------------------------- > 1) connect(the same > client SocketAddress) > 2)fireSessionCreated > 3)putIfAbsent > 4)disconnect > > 5)connect(the same client SocketAddress) > 6)fireSessionCreated > 7)putIfAbsent > 8)fireSessionDestroyed > 9)remove > > 10)disconnect > 11)fireSessionDestroyed > 12)get fail > > > > I changed the mina source IoServiceListenerSupport.java > > org.apache.mina.common.support.IoServiceListenerSupport > ... > > public void fireSessionDestroyed(IoSession session) { > boolean lastSession = false; > SocketAddress serviceAddress = session.getServiceAddress(); > > // Get the session set. > Set<IoSession> sessions = managedSessions.get(serviceAddress); > // Ignore if unknown. > if (sessions == null) { > // return; <-- delete > } else { // <-- add > > sessions.remove(session); > > // Try to remove the remaining empty session set after > removal. > if (sessions.isEmpty()) { > lastSession = > managedSessions.remove(serviceAddress, sessions); > } > } // <-- add > .... > > then the Create, Destroy call mismatch was cleared. > but I don't know this is correct solution. > > Would you tell me this is correct or not? > > I think this situation is very rare but... > I hope the mina is the best network framework > and this situation shoud be also considered. > > > Thank you > > J. H. Cha