學習mina同步與異步網絡通訊(二)——服務器端

寫個服務器端,做測試。

服務器端與客戶端最大的區別是使用IoAcceptor和IoHandler

核心代碼:

package com.lele.test.mina.server.acceptor;

import java.io.IOException;
import java.net.InetSocketAddress;

import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

import com.lele.test.mina.server.acceptor.codec.CodecFactory;
import com.lele.test.mina.server.acceptor.handle.MinaServerHandler;

public class MinaAcceptor{

	private int port = 1234;

	// socket接收器
	private SocketAcceptor acceptor;
	private static MinaAcceptor minaAcceptor;
	private SocketSessionConfig sessionConfig;
	//單例模式
	public static  MinaAcceptor getInstances(){
		if (null == minaAcceptor) {                 
			minaAcceptor = new MinaAcceptor();      
        	}              
        	return minaAcceptor;    
	}
	protected MinaAcceptor() {
		acceptor = new NioSocketAcceptor();
		//此處的過濾器與客戶端代碼一樣,使用自定義的CodecFactory
		acceptor.getFilterChain().addLast("codec",
				new ProtocolCodecFilter(new CodecFactory(false)));
		acceptor.getFilterChain().addLast("logger", new LoggingFilter());
		sessionConfig = getAcceptor().getSessionConfig();
		// 設置IoSession的read()方法爲可用,默認爲false,這行可以去掉,服務器端的read是被封裝的,不需要定義IoSession,也不涉及到read(),應該是accptor內部實現了。
		sessionConfig.setUseReadOperation(true);
		//設置處理器
		acceptor.setHandler(new MinaServerHandler());
		try {
			//註冊端口。
			acceptor.bind(new InetSocketAddress(port));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public SocketAcceptor getAcceptor() {
		return acceptor;
	}

	public void setAcceptor(SocketAcceptor acceptor) {
		this.acceptor = acceptor;
	}

	public SocketSessionConfig getSessionConfig() {
		return sessionConfig;
	}

	public void setSessionConfig(SocketSessionConfig sessionConfig) {
		this.sessionConfig = sessionConfig;
	}

}
handler:

package com.lele.test.mina.server.acceptor.handle;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

import com.lele.test.mina.server.acceptor.pojo.ApplyKeyRequest;
import com.lele.test.mina.server.acceptor.pojo.ApplyKeyResponse;

public class MinaServerHandler extends IoHandlerAdapter {
	
	public void sessionCreated(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("session is created!");
	}

	public void sessionOpened(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("session is Opened!");
	}

	public void sessionClosed(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("session is Closed!");
	}

	public void sessionIdle(IoSession session, IdleStatus status)
			throws Exception {
		// TODO Auto-generated method stub

	}

	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		// TODO Auto-generated method stub

	}

	public void messageReceived(IoSession session, Object message)
			throws Exception {
		if(message instanceof UserReq){
			
			System.out.println(((UserRequest) message).getUsername());
		}
		//準備返回的數據!
		UserRes a = new UserRes();
		a.setSay("Mr.S say helloWorld!!!");
		//此處與客戶端的write一致,會調用filter進行轉碼,轉成Byte[]
		session.write(a);
	}

	public void messageSent(IoSession session, Object message) throws Exception {
		// TODO Auto-generated method stub

	}

}
接收完數據後,會自動關閉session。創建SESSION與打開session都是自動完成的。只要註冊了handle~


查看一下SocketAcceptor的代碼,繼承自IoAcceptor~

幾個接口,獲取配置、IP端口等信息、是否暫停等。

在IoAcceptor中,有一個接口

IoSession newSession(SocketAddress remoteAddress, SocketAddress localAddress);

將會話綁定到客戶端與服務端。怎麼綁定的,沒找到啊。。。

public void messageReceived(IoSession session, Object message)
			throws Exception {
		if(message instanceof UserReq){
			
			System.out.println(((UserRequest) message).getUsername());
		}
		//準備返回的數據!
		UserRes a = new UserRes();
		a.setSay("Mr.S say helloWorld!!!");
		//此處與客戶端的write一致,會調用filter進行轉碼,轉成Byte[]
		session.write(a);
	}
服務啓動時加了過濾器,所以這面message讀過來就已經解碼成UserReq了

補充:

跟蹤一下服務器端的線程,

MINA一共三種線程。

 第一類線程:NioSocketAcceptor 唯一。用於bind監聽端口,bind一次創建一個。客戶端發送請求時,將請求發送給第二類線程處理。
 第二類線程:Nioprocessor 處理客戶端請求。每個請求1個線程。滿了等待。acceptor = new NioSocketAcceptor(4);創建最大4個線程。handler中的sessionCreated
 第三類線程:處理業務邏輯的線程,使用過濾器添加。第二類線程接收請求後轉給第三類請求處理。handler中的從sessionOpen到close。
如果不添加過濾器,那麼業務處理將在第二類線程中完成。


		acceptor = new NioSocketAcceptor(4);
		//第三類線程
		//acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
		
		


使用可重用的線程池,當現有線程有可用則繼續使用,如沒有,創建新的線程。滿了繼續添加新的(PS:適合短連接。用完就銷燬。提高性能啊!有機會測試一下。看最多能整多少個線程~)
Executors.newCachedThreadPool()
還有一種,創建固定個數的線程池,也是可重用的,只不過限制個數nThreads,滿了會阻塞

newFixedThreadPool(int nThreads)


需要惡補一下線程方面的知識了~



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章