Naga 基于NIO的socket框架

公司游戏端和游戏后台端的通信用的是基于NIO的socket框架。
由于从未使用过socket 然后最近要接触到这方面的工作了,拿到代码看了一下流程。
整理如下:

socket中三次握手,四次挥手的体现

三次握手

a.客户端向服务器发送一个SYN J
b.服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1
c.客户端再想服务器发一个确认ACK K+1
在这里插入图片描述

当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。
总结:客户端的connect在三次握手的第二个次返回,而服务器端的accept在三次握手的第三次返回

四次握手
在这里插入图片描述

某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
接收到这个FIN的源发送端TCP对它进行确认。 这样每个方向上都有一个FIN和ACK

1.Naga框架中的常用类

NIOService :创建NIO流的服务对象

NIOServerSocket :相当于IO中ServerSocket

NIOSocket 相当于IO中Socket

ServerSocketObserverAdapter:服务器端ServerSocket的监听适配器

SocketObserver 客户端ServerSocket的监听事件

SocketObserverAdapter:客户端SOcket器端的监听适配器

2.服务端代码
SocketServerListener.java
//由于Socket应该基于项目启动,所以在ServletContextListener中重写contextInitialized方法
public class SocketServerListener implements
		javax.servlet.ServletContextListener {

	private static final Log logger = LogFactory.getLog(SocketServerListener.class);
	private static NIOServerSocket serverSocket = null;
	private static NIOService service = null;
	
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
//		logger.info("[Application]:Close Socket Server.");
		if(serverSocket != null && serverSocket.isOpen()){
			logger.info("[Application]:Close Socket...");
			serverSocket.close();
		}
		if(service != null && service.isOpen()){
			logger.info("[Application]:Close Socket Service...");
			service.close();
		}
	}

	@Override
	public void contextInitialized(ServletContextEvent arg0) {
//		logger.info("Init Socket Server...");
		ServletContext servletContext = arg0.getServletContext();
		WebApplicationContext webApplicationContext = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
		ContextHolder.getInstance().setApplicationContext(webApplicationContext);
		
		new Thread() {
			public void run() {
				try {
				    //创建一个NIOService服务对像
					service = new NIOService();
					//创建一个NIOServerSocket服务端对象 端口号:700
					serverSocket = service.openServerSocket(7000);
					//服务端添加相关的监听器 用于监听socket信息
					serverSocket.listen(new ServerSocketObserverAdapter() {
					    //当连接成功时
						public void newConnection(NIOSocket nioSocket) {
//							logger.info("Received connection: " + nioSocket);
							try {
							   //保证Socket还是连接着的
								nioSocket.socket().setKeepAlive(true);
							} catch (SocketException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							// Listen on the connection.
					       //监听到Socket信息是处理方式
					       //备注此处采用的是Socket的观察者适配器
							nioSocket.listen(new SocketObserverAdapter());
						}
					});
					
					serverSocket.setConnectionAcceptor(ConnectionAcceptor.ALLOW);
					while(true){
						service.selectBlocking();
					}
				} catch (Exception e) {
					if(serverSocket != null){
						serverSocket.close();
					}
					logger.error(e.getMessage());
				}
			}
		}.start();
	}
}
SocketObserverAdapter.java
/**
 * 
 */
package com.ceapon.fire.ams.network;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

import naga.NIOSocket;
import naga.SocketObserver;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author shixing
 * 
 */
public class SocketObserverAdapter implements SocketObserver {
	
	private static final Log logger = LogFactory.getLog(SocketObserverAdapter.class);
	
	private ByteBuffer byteBuffer;

	public SocketObserverAdapter(){
	
		byteBuffer = ByteBuffer.allocate(8192);//分配了一段内存空间,作为缓存
		byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
		
	}
    /**
    * 连接发生异常时候的处理
    **/
	public void connectionBroken(NIOSocket nioSocket, Exception exception)
	{
		byteBuffer = ByteBuffer.allocate(0);
		byteBuffer = null;
		//SessionCache.getInstance().removeSession(nioSocket.getIp(), nioSocket.getPort());
		//logger.info("Client "+ nioSocket.getTimeOpen()+ " :" + nioSocket.getIp() + ":" + nioSocket.getPort() + " disconnected.");
	}
   /**
    * 接收数据包的信息
    **/

	public void packetReceived(NIOSocket socket, byte[] packet)
	{
		try {
			byteBuffer.put(packet);
			//InputStream inputStream =   new ByteArrayInputStream(byteBuffer.array());
			//MessageInputStream mis = new MessageInputStream(inputStream);
			short re
		}
		catch(Exception e)
		{
			
		}
	}
	
	
	
	public void packetReceived2(NIOSocket socket, byte[] packet)
	{
//		logger.info("[WARN]-------socket start work-----------");
		//logger.info("SocketObserverAdapter packetReceived...");
		try {
			InputStream inputStream =   new ByteArrayInputStream(packet);
			MessageInputStream mis = new MessageInputStream(inputStream);
			MessageOutputStream os = new MessageOutputStream(socket.socket().getOutputStream());
			//新开启一个线程去处理业务
			HandlerUtil.handle(new LoginHandlerForTest());
			// Create the outgoing packet.
			out.flush();
			//写数据到客户端
			socket.write(byteArrayOutputStream.toByteArray());
			
			// Close after the packet has finished writing.
			//关闭当前写入流
			socket.closeAfterWrite();
		}catch (Exception e) {
			socket.close();
			e.printStackTrace();
		}
    }
    /**
    *连接打开时候执行的操作
    **/
	public void connectionOpened(NIOSocket nioSocket)
	{
//		logger.info("Receive MSG_ID_LOGIN_GSAS_PONG...");
	}

    public void packetSent(NIOSocket socket, Object tag)
    {
    }
     /**
	  * 写数据的到客户端  相当于返回信息给发送方
	  * @param socket
	  * @param packet
	*/
	@SuppressWarnings("unused")
	public void notifyReadPacket(NIOSocket socket, byte[] packet)   
	{     
		socket.write(packet);   
	} 

}



接下来是模拟客户端向服务器端发送channelID 返回 content

HandlerUtil.java
public class HandlerUtil {
	
	public static void handle(Runnable handler){
		new Thread(handler).start();
	}
}

testHandler .java
public class testHandler implements Runnable  {
	
	private static final Log logger = LogFactory.getLog(testHandler .class);
	
	private testRequset request;
	private NIOSocket socket;
	public testHandler (NIOSocket socket,testRequset request){
		this.request = request;
		this.socket  = socket;
	}
	
	@Override
	public void run() {
		try {
			MessageOutputStream os = new MessageOutputStream(socket.socket().getOutputStream());
            //业务逻辑
            String content="你是傻蛋";
            testResponse response= new testResponse ();
			response.setContent(content);
			Protocol.sendResponse(os, response);
			socket.write(os.getBuf());
    		os.clear();
		}
		catch(Exception e)
		{
			logger.info("testHandler error"+JSONValue.toJSONString(request));
			e.printStackTrace();
		}
	}
}
testRequset .java
	private int channelID;
		public int getChannelID() {
			return channelID;
		}

		public void setChannelID(int channelID) {
			this.channelID = channelID;
		}
		//读写数据
		public boolean encode(MessageOutputStream os) {
			super.encode(os);
			os.write(channelID);
			return true;
		}

		public boolean decode(MessageInputStream is) throws Exception {
			super.decode(is);
			channelID = is.read(channelID);
			return true;
		}

testResponse.java
	private String content;

	public boolean encode(MessageOutputStream os) {
		super.encode(os);
		os.write(content);
		return true;
	}

	public boolean decode(MessageInputStream is) throws Exception {
		super.decode(is);
		content = is.read(content);
		return true;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}
	

客户端

由于我暂时还没看到客户端的写法 于是查阅资料,如果有错,在沟通

package com.easyway.space.sockets.naga;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetAddress;
 
import naga.NIOService;
import naga.NIOSocket;
import naga.SocketObserver;
import naga.SocketObserverAdapter;
import naga.packetreader.RegularPacketReader;
import naga.packetwriter.RegularPacketWriter;
 
/**
 * Naga的远程客户端验证 的客户端的代码
 * @author longgangbai
 *
 */
public class NagaClient
{
	NagaClient()
	{}
 
	/**
	 * Make a login request to the server.
	 *
	 * @param args assumed to be 4 strings representing host, port, account and password.
	 */
	public static void main(String... args)
	{
		try
		{
			// Parse arguments.
			String hostName = "localhost";
			int port = 8090;
			//设置登录的账号信息
			String account ="Admin";
			String password = "password";
 
			// Prepare the login packet, packing two UTF strings together
			// using a data output stream.
			//将信息写入流中发送到服务端
			ByteArrayOutputStream stream = new ByteArrayOutputStream();
			DataOutputStream dataStream = new DataOutputStream(stream);
			dataStream.writeUTF(account);
			dataStream.writeUTF(password);
			dataStream.flush();
			final byte[] content = stream.toByteArray();
			dataStream.close();
 
			// Start up the service.
			//设置NIOService的服务对象
			NIOService service = new NIOService();
 
			//获取相关的ip的信息
			InetAddress intaddress=InetAddress.getByName(hostName);
			// Open our socket.
			//打开当前请求的Socket的对象
			NIOSocket socket = service.openSocket(intaddress.getHostAddress(), port);
 
			// Use regular 1 byte header reader/writer
			//设置读写信息包的信息
			socket.setPacketReader(new RegularPacketReader(1, true));
			socket.setPacketWriter(new RegularPacketWriter(1, true));
 
			// Start listening to the socket.
			//添加相关的监听事件用于监听客户端
			socket.listen(new SocketObserver()
			{
				/** A null object used as the default observer */
				SocketObserver NULL = new SocketObserverAdapter();
				/**
				 * 连接成功时的相关的操作
				 */
				public void connectionOpened(NIOSocket nioSocket)
				{
					System.out.println("Sending login...");
					nioSocket.write(content);
				}
                //用于接收服务端的信息
				public void packetReceived(NIOSocket socket, byte[] packet)
				{
					try
					{
						// Read the UTF-reply and print it.
						String reply = new DataInputStream(new ByteArrayInputStream(packet)).readUTF();
						System.out.println("Reply was: " + reply);
						// Exit the program.
						System.exit(0);
					}
					catch (Exception e)
					{
						e.printStackTrace();
					}
				}
                //用于接受服务端连接发生异常时的处理方式
				public void connectionBroken(NIOSocket nioSocket, Exception exception)
				{
					System.out.println("Connection failed.");
					// Exit the program.
					System.exit(-1);
				}
			});
			// Read IO until process exits.
			//采用阻塞式读取IO信息,知道进程退出
			while (true)
			{
				service.selectBlocking();
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值