这里比较复杂的莫过于spring的配置了那就先上配置applicationContext.xml
mina的配置在最下面
<spring -- mina >这个 之上的 配置有velocity和memcache还有springjdbc,自动装配,json对象支持(注解@ResponseBody), 切面事务管理 , 当然这些大家能用的上的 拿走 用不上删掉(跟没说一样)
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <context:property-placeholder location="classpath:jdbc.properties" /> <bean id="stringConverter" class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> </list> </property> </bean> <bean id="exceptionResolver" class="com.util.ExceptionHandler"/> <!-- 输出对象转JSON支持 --> <bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="stringConverter"/> <ref bean="jsonConverter" /> </list> </property> </bean> <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 --> <!-- <context:component-scan base-package="com.controller" /> <context:component-scan base-package="com.service" /> <context:component-scan base-package="com.dao" /> --> <context:component-scan base-package="com" /> <!-- 配置数据源 destroy-method="close"--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass"> <value>${jdbc.driverClassName}</value> </property> <property name="jdbcUrl"> <value>${jdbc.url}</value> </property> <property name="user"> <value>${jdbc.username}</value> </property> <property name="password"> <value>${jdbc.password}</value> </property> <!--连接池中保留的最小连接数。 --> <property name="minPoolSize"> <value>5</value> </property> <!--连接池中保留的最大连接数。Default: 15 --> <property name="maxPoolSize"> <value>30</value> </property> <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> <property name="initialPoolSize"> <value>10</value> </property> <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --> <property name="maxIdleTime"> <value>60</value> </property> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> <property name="acquireIncrement"> <value>5</value> </property> <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --> <property name="maxStatements"> <value>0</value> </property> <!--每60秒检查所有连接池中的空闲连接。Default: 0 --> <property name="idleConnectionTestPeriod"> <value>60</value> </property> <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 --> <property name="acquireRetryAttempts"> <value>30</value> </property> <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 获取连接失败后该数据源将申明已断开并永久关闭。Default: false --> <property name="breakAfterAcquireFailure"> <value>true</value> </property> <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable 等方法来提升连接测试的性能。Default: false --> <property name="testConnectionOnCheckout"> <value>false</value> </property> <property name="automaticTestTable"> <value>true</value> </property> </bean> <!-- 配置Jdbc模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource" /> <!-- 通过AOP配置提供事务增强,让controller包下所有Bean的所有方法拥有事务 --> <!-- <aop:config proxy-target-class="true"> <aop:pointcut id="serviceMethod" expression=" execution(* com.controller..*(..))" /> <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" /> </tx:attributes> </tx:advice> --> <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> <!-- VM视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="requestContextAttribute" value="rc"></property> <property name="cache" value="true"/> <property name="prefix" value=""/> <property name="suffix" value=".vm"/> <property name="contentType"><value>text/html;charset=UTF-8</value></property> <property name="dateToolAttribute"><value>dateTool</value></property> <property name="numberToolAttribute"><value>numberTool</value></property> </bean> <!-- 指定模板视图存放位置,以及编码格式 --> <bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="resourceLoaderPath" value="/WEB-INF/velo/"/> <property name= "velocityProperties"> <props> <prop key="input.encoding">utf-8</prop> <prop key="output.encoding">utf-8</prop> </props> </property> </bean> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> <!-- 访问数据库前,查询MEMCACHED缓存服务器 --> <!-- <bean id="memcachedInterceptor" class="com.interceptor.MemcachedInterceptor"></bean> <aop:config> <aop:pointcut expression="execution(* select*(..))" id="memcachedPointCut"/> <aop:aspect id="memcachedAspect" ref="memcachedInterceptor"> <aop:around pointcut-ref="memcachedPointCut" method="aronud"/> </aop:aspect> </aop:config> --> <!-- 官方文档地址 http://code.google.com/p/xmemcached/wiki/Spring_Integration --> <bean id="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder" p:connectionPoolSize="20" p:failureMode="true"> <constructor-arg> <list> <bean class="java.net.InetSocketAddress"> <constructor-arg> <value>你的memcache的地址</value> </constructor-arg> <constructor-arg> <value>11211</value> </constructor-arg> </bean> <!-- <bean class="java.net.InetSocketAddress"> --> <!-- <constructor-arg> --> <!-- <value>192.168.1.2</value> --> <!-- </constructor-arg> --> <!-- <constructor-arg> --> <!-- <value>10002</value> --> <!-- </constructor-arg> --> <!-- </bean> --> <!-- <bean class="java.net.InetSocketAddress"> --> <!-- <constructor-arg> --> <!-- <value>192.168.1.3</value> --> <!-- </constructor-arg> --> <!-- <constructor-arg> --> <!-- <value>10003</value> --> <!-- </constructor-arg> --> <!-- </bean> --> <!-- <bean class="java.net.InetSocketAddress"> --> <!-- <constructor-arg> --> <!-- <value>192.168.1.4</value> --> <!-- </constructor-arg> --> <!-- <constructor-arg> --> <!-- <value>4</value> --> <!-- </constructor-arg> --> <!-- </bean> --> </list> </constructor-arg> <constructor-arg> <list> <value>1</value> <!-- <value>2</value> --> <!-- <value>3</value> --> <!-- <value>4</value> --> </list> </constructor-arg> <property name="commandFactory"> <bean class="net.rubyeye.xmemcached.command.TextCommandFactory" /> </property> <property name="sessionLocator"> <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator" /> </property> <property name="transcoder"> <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" /> </property> </bean> <bean id="memcachedClient" factory-bean="memcachedClientBuilder" factory-method="build" destroy-method="shutdown" /> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:defaultEncoding="utf-8"/> <mvc:interceptors> <!-- 拦截所有请求 <bean class="com.etoak.util.LoginCheck2"></bean>--> <mvc:interceptor> <mvc:mapping path="/dashboard"/> <mvc:mapping path="/dashboard/**"/> <mvc:mapping path="/setting"/> <mvc:mapping path="/setting/**"/> <bean class="com.interceptor.LoginCheck"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.interceptor.CityCheck"></bean> </mvc:interceptor> </mvc:interceptors> <!-- spring && mina --> <!-- executorFilter多线程处理 --> <bean id="executorFilter" class="org.apache.mina.filter.executor.ExecutorFilter" /> <bean id="mdcInjectionFilter" class="org.apache.mina.filter.logging.MdcInjectionFilter"> <constructor-arg value="remoteAddress" /> </bean> <bean id="codecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter"> <constructor-arg> <!-- <bean class="org.apache.mina.filter.codec.textline.TextLineCodecFactory" />--> <!-- 处理对象流时候用ObjectSerializationCodecFactory --> <!-- <bean class="org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory" /> --> <bean class="com.umaiw.socket.ServerCodeFactory" /> </constructor-arg> </bean> <bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" /> <bean id="filterChainBuilder" class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder"> <property name="filters"> <map> <entry key="executor" value-ref="executorFilter" /> <entry key="mdcInjectionFilter" value-ref="mdcInjectionFilter" /> <entry key="codecFilter" value-ref="codecFilter" /> <entry key="loggingFilter" value-ref="loggingFilter" /> </map> </property> </bean> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="java.net.SocketAddress"> <bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" /> </entry> </map> </property> </bean> <!-- session config --> <bean id="sessionConfig" factory-bean="ioAcceptor" factory-method="getSessionConfig" > <property name="readerIdleTime" value="50"/> </bean> <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor" init-method="bind" destroy-method="unbind"> <property name="defaultLocalAddress" value=":10000" /> <property name="handler" ref="dataHandler" /> <property name="filterChainBuilder" ref="filterChainBuilder" /> <property name="reuseAddress" value="true" /> </bean> <bean id="dataHandler" class="com.umaiw.socket.DataHandler"> </bean> <!--这里是udp的部分 如果想用请下载udp部分的代码 会在最下面有下载--> <!- <bean id="udpAcceptor" class="org.apache.mina.transport.socket.nio.NioDatagramAcceptor" init-method="bind" destroy-method="unbind"> <property name="defaultLocalAddress" value=":10001" /> <property name="handler" ref="UdpHandler" /> <property name="filterChainBuilder" ref="filterChainBuilder" /> </bean> <bean id="UdpHandler" class="com.umaiw.socket.UdpHandler"> </bean> --> </beans>
如果需要数据库连接的话 再src下面再写个jdbc.properties具体怎么写大家都会把 好吧给个例子
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://你的数据库地址哦:3306/umaiwtest?relaxAutoCommit=true&zeroDateTimeBehavior=convertToNull
jdbc.username=test
jdbc.password=test
然后是DataHandler 处理各种事件的地方
其中的messageRecive方法里调用的
String result=constants.getClassName(Long.parseLong(command));
Command cmd = (Command)constants.newCommand(result);
cmd.action(session, other);
则是吧处理的业务逻辑写成了实现command的接口都有一个action方法
然后动态加载command这个对应名字类的方法
这里是按 : 来分隔参数的
package com.umaiw.socket; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.mina.core.future.CloseFuture; import org.apache.mina.core.future.IoFuture; import org.apache.mina.core.future.IoFutureListener; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.model.UserSession; import com.model.umaiw_app_system; import com.service.GetInitKeyService; import com.service.implement.GetInitKeyServiceImpl; import com.umaiw.command.Command; import com.umaiw.command.Constants; import com.umaiw.command.SocketModel; import com.util.DesUtil; @Component("DataHandler") public class DataHandler extends IoHandlerAdapter implements Runnable{ @Autowired private Constants constants; private final static Logger log = LoggerFactory.getLogger(DataHandler.class); private final Set<IoSession> sessions = Collections.synchronizedSet(new HashSet<IoSession>()); //private UserSession UserSession; @Autowired private static Map<String,IoSession> users = Collections.synchronizedMap(new HashMap<String,IoSession>()); @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { log.error(" 有异常发生时被触发exceptionCaught。",cause); session.close(true); } @Override public void sessionCreated(IoSession session) throws Exception { log.info("当创建一个新连接时被触发,即当开始一个新的Session时被触发。"); log.info("创建一个新连接:{}", session.getRemoteAddress()); /*//50秒无读写操作就触发idele session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 50);*/ sessions.add(session); log.info("并发的个数:\t"+sessions.size()); session.setAttribute("command",1); messageSentSingle(session, "创建了一个socket连接哦"); } @Override public void messageReceived(IoSession session, Object message) throws Exception { log.info("服务器接收到数据: {}", message); String[] mes=message.toString().split(":"); String version=mes[0];//协议版本号 String ID=mes[1];//包ID(10进制) String mark=mes[2];//唯一标识 String mobile=mes[3];//手机号码 String command=mes[4];//命令ID(10进制) String[] other=new String[mes.length*2]; if(mes.length>5){ for(int i=5;i<mes.length;i++){ int x=0; other[x]=mes[i]; x++; } } if(mobile==null){ mobile="1"; } session.setAttribute("mobile",mobile); String result=constants.getClassName(Long.parseLong(command)); Command cmd = (Command)constants.newCommand(message); cmd.action(session, message); Object oldpacket_id=session.getAttribute("packet_id"); if(oldpacket_id!=null){ session.setAttribute("oldpacket_id",oldpacket_id); } String packet_id=new Date().getTime()+""; session.setAttribute("packet_id",packet_id); session.setAttribute("command",Integer.parseInt(command)); // messageSentSingle(session, "业务处理完了"); } public static void messageSentAll( Object message) throws Exception { log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message); // 向所有客户端发送的数据 SocketModel socm=new SocketModel(new Date().getTime()+"", "", 5, message); String send=socm.toString(); Collection<IoSession> sessions = users.values(); for (IoSession sess : sessions) { sess.write(send); } } public static void messageSentSingle(IoSession session, Object message) throws Exception { log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message); // 向所有客户端发送的数据 Integer command=(Integer) session.getAttribute("command"); SocketModel socm=new SocketModel(new Date().getTime()+"", "", command, message); String send=socm.toString(); session.write(send); } public static void messageSentPart( Object message,String city_id) throws Exception { log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message); Object[] key=users.keySet().toArray(); for (int i = 0; i < key.length; i++) { if(key[i].toString().contains(city_id)){ IoSession iosession=users.get(key[i]); SocketModel socm=new SocketModel(new Date().getTime()+"", "", 5, message); String send=socm.toString(); iosession.write(send); } } // 向所有客户端发送的数据 } public static Map<String, IoSession> getUsers() { return users; } @Override public void sessionClosed(IoSession session) throws Exception { log.info("关闭当前session:{}#{}", session.getId(), session.getRemoteAddress()); CloseFuture closeFuture = session.close(true); closeFuture.addListener(new IoFutureListener<IoFuture>() { public void operationComplete(IoFuture future) { if (future instanceof CloseFuture) { ((CloseFuture) future).setClosed(); log.info("sessionClosed CloseFuture setClosed-->{},", future.getSession().getId()); } } }); UserSession userSession= (UserSession) session.getAttribute("UserSession"); String mobile=(String) session.getAttribute("mobile"); if(null!=mobile&&userSession!=null){ users.remove(mobile+"+"+userSession.getCity_id()); } sessions.remove(session); log.info("关闭的连接的剩余的个数:\t"+sessions.size()); } @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { // session.close(); log.info("IDLE " + session.getIdleCount(status)+"次;"+"user个数"+users.size()+"sessions个数"+sessions.size()); if(session.getIdleCount(status) > 5){ log.info("连接空闲= " + session.getIdleCount(status)+",触发session关闭"); session.close(true); } } @Override public void sessionOpened(IoSession session) throws Exception { log.info("进入当打开一个连接时被触发sessionOpened!"); log.info("打开一个session:{}#{}", session.getId(), session.getBothIdleCount()); try { super.sessionOpened(session); } catch (Exception e) { log.error("",e); } } @Override public void messageSent(IoSession session, Object message) throws Exception { log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message); try { super.messageSent(session, message); } catch (Exception e) { log.error("",e); } } } }
然后是处理业务逻辑的command接口 和实现它的类(这里就举1个例子,多写业务处理 就再多些点实现类就行)
command.java
package com.umaiw.command; import org.apache.mina.core.session.IoSession; public interface Command { public void action(IoSession session,String[] other) ; }
UMMSG_TCP_SENDINFORMATIONTOSERVER.java(业务逻辑处理)
package com.umaiw.command; import org.apache.mina.core.session.IoSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import com.model.UserSession; import com.service.LoginService; import com.service.implement.LoginServiceImpl; import com.umaiw.socket.DataHandler; @Component("UMMSG_TCP_SENDINFORMATIONTOSERVER") public class UMMSG_TCP_SENDINFORMATIONTOSERVER implements Command { @Autowired private LoginService loginService ; @Override public void action(IoSession session, String[] param) { String mobile=(String) session.getAttribute("mobile"); UserSession user= loginService.getUserSession(mobile); session.setAttribute("UserSession",user); DataHandler.getUsers().put(mobile+"+"+user.getCity_id(), session); // DataHandler.messageSentSingle(session, s); } }
接下来是根据传过来的command来找是哪个处理类的类
Constants.java
这里注册了三个类(上面给了一个类UMMSG_TCP_SENDINFORMATIONTOSERVER的例子,别的照着写就行啦)
package com.umaiw.command; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component("Constants") public class Constants { @Autowired private UMMSG_TCP_CHECKCLIENT uMMSG_TCP_CHECKCLIENT; @Autowired private UMMSG_TCP_MAKESURECEIVE uMMSG_TCP_MAKESURECEIVE; @Autowired private UMMSG_TCP_SENDINFORMATIONTOSERVER uMMSG_TCP_SENDINFORMATIONTOSERVER; @Autowired private Map<String, Object> registry = new HashMap<String, Object>(); @Autowired private void res() { // 2、客户端发送口令供服务器端验证 registry.put(UMMSG_TCP_CHECKCLIENT_name, uMMSG_TCP_CHECKCLIENT); // 3、客户端发送身份信息给服务器 registry.put(UMMSG_TCP_SENDINFORMATIONTOSERVER_name, uMMSG_TCP_SENDINFORMATIONTOSERVER); // 4、客户端发送回执给服务器 registry.put(UMMSG_TCP_MAKESURECEIVE_name, uMMSG_TCP_MAKESURECEIVE); } // 方法对应值与类名 // 2、客户端发送口令供服务器端验证 public static final int UMMSG_TCP_CHECKCLIENT_code = 0x00000002; public static final String UMMSG_TCP_CHECKCLIENT_name = "UMMSG_TCP_CHECKCLIENT"; // 3、客户端发送身份信息给服务器 public static final int UMMSG_TCP_SENDINFORMATIONTOSERVER_code = 0x00000003; public static final String UMMSG_TCP_SENDINFORMATIONTOSERVER_name = "UMMSG_TCP_SENDINFORMATIONTOSERVER"; // 4、客户端发送回执给服务器 public static final int UMMSG_TCP_MAKESURECEIVE_code = 0x00000004; public static final String UMMSG_TCP_MAKESURECEIVE_name = "UMMSG_TCP_MAKESURECEIVE"; // 注册到registry集合里好使用 public String getClassName(long code) { if (code == UMMSG_TCP_SENDINFORMATIONTOSERVER_code) { return UMMSG_TCP_SENDINFORMATIONTOSERVER_name; } else if (code == UMMSG_TCP_SENDINFORMATIONTOSERVER_code) { return UMMSG_TCP_SENDINFORMATIONTOSERVER_name; } else if (code == UMMSG_TCP_MAKESURECEIVE_code) { return UMMSG_TCP_MAKESURECEIVE_name; } else if (code == UMMSG_TCP_CHECKCLIENT_code) { return UMMSG_TCP_CHECKCLIENT_name; } return null; } public Object newCommand(String name) { return registry.get(name); } // 获得无符号值 public static int getUnsignedValue(byte bt) { int i = bt; if (bt < 0) { i = 257 + i; } return i; } // 获得无符号值 public static long getLongValue(byte[] bt) { long l = 0; for (int i = 0; i < bt.length; i++) { l = (l << 8) | (bt[i] & 0xff); } return l; } public String getClassName(byte[] bt) { return getClassName(getLongValue(bt)); } /** * @since Integer转换byte[] * @param len * @return */ public static byte[] getByteByInt(Integer len, int buffer) { byte[] b = new byte[buffer]; for (int i = b.length - 1; i > -1; i--) { b[i] = new Integer(len & 0xff).byteValue();// 将最高位保存在最低位 len = len >> 8; // 向右移8位 } return b; } public static byte[] getByteByStr(String len, int buffer) { byte[] bt = new byte[buffer]; System.arraycopy(len.getBytes(), 0, bt, 0, len.getBytes().length); return bt; } public static void main(String[] args) { // getByteByStr("123", 6); // byte[] bt = new byte[4]; // bt[0] = (byte) 0x00; // bt[1] = (byte) 0x00; // bt[2] = (byte) 0x00; // bt[3] = (byte) 0x01; // System.out.println(Constants.getLongValue(bt)); // System.out.println(Constants.getLongValue(Constants // .getByteByInt(110, 4))); // getByteByInt(0x10000001, 4); System.err.println(Integer.MAX_VALUE); } }
接下来是socketmodel 就是用来整理发送消息的格式的
SocketModel.java
package com.umaiw.command; public class SocketModel { private String version="UM"; private String id; private String mark=""; private String mobile; private Object other; private Integer command; public SocketModel( String id, String mobile, Integer command,Object other) { this.id = id; this.mobile = mobile; this.other = other; this.command = command; } public String toString() { return version+":"+id+":"+mark+":"+mobile+":"+command+":"+other+(char)7; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getMark() { return mark; } public void setMark(String mark) { this.mark = mark; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public Object getOther() { return other; } public void setOther(Object other) { this.other = other; } public Integer getCommand() { return command; } public void setCommand(Integer command) { this.command = command; } }
最后是mina必备的codefactory和decode,encode
ServerCodeFactory.java
package com.umaiw.socket; import java.nio.charset.Charset; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolDecoder; import org.apache.mina.filter.codec.ProtocolEncoder; import org.apache.mina.filter.codec.textline.LineDelimiter; import org.apache.mina.filter.codec.textline.TextLineDecoder; import org.apache.mina.filter.codec.textline.TextLineEncoder; public class ServerCodeFactory implements ProtocolCodecFactory { private final ProtocolEncoder encoder; private final ProtocolDecoder decoder; /*final static char endchar = 0x1a;*/ final static char endchar = 0x0d; public ServerCodeFactory() { this(Charset.forName("utf-8")); } public ServerCodeFactory(Charset charset) { encoder = new CharsetEncoder(); decoder = new CharsetDecoder(); } @Override public ProtocolDecoder getDecoder(IoSession session) throws Exception { // TODO Auto-generated method stub return decoder; } @Override public ProtocolEncoder getEncoder(IoSession session) throws Exception { // TODO Auto-generated method stub return encoder; } public ProtocolEncoder getEncoder() { return encoder; } public ProtocolDecoder getDecoder() { return decoder; } }
CharsetDecoder.java (这里用(char)7当结束标志)
package com.umaiw.socket; import java.nio.charset.Charset; import org.apache.log4j.Logger; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolDecoder; import org.apache.mina.filter.codec.ProtocolDecoderOutput; /** * <b>function:</b> 字符解码 * @author hoojo * @createDate 2012-6-26 上午11:14:18 * @file CharsetDecoder.java * @package com.hoo.mina.code * @project ApacheMiNa * @blog http://blog.csdn.net/IBM_hoojo * @email [email protected] * @version 1.0 */ public class CharsetDecoder implements ProtocolDecoder { private final static Logger log = Logger.getLogger(CharsetDecoder.class); private final static Charset charset = Charset.forName("UTF-8"); // 可变的IoBuffer数据缓冲区 private IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true); @Override public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { log.info("#########decode#########"); // 如果有消息 while (in.hasRemaining()) { // 判断消息是否是结束符,不同平台的结束符也不一样; // windows换行符(\r\n)就认为是一个完整消息的结束符了; UNIX 是\n;MAC 是\r byte b = in.get(); if (b == (char)7) { buff.flip(); byte[] bytes = new byte[buff.limit()]; buff.get(bytes); String message = new String(bytes, charset); buff = IoBuffer.allocate(100).setAutoExpand(true); // 如果结束了,就写入转码后的数据 out.write(message); log.info("message: " + message); } else { buff.put(b); } } } @Override public void dispose(IoSession session) throws Exception { log.info("#########dispose#########"); log.info(session.getCurrentWriteMessage()); } @Override public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception { log.info("#########完成解码#########"); } }
CharsetEncoder.java
package com.umaiw.socket; import java.nio.charset.Charset; import org.apache.log4j.Logger; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolEncoder; import org.apache.mina.filter.codec.ProtocolEncoderOutput; import org.apache.mina.filter.codec.textline.LineDelimiter; /** * <b>function:</b> 字符编码 * @author hoojo * @createDate 2012-6-26 上午11:32:05 * @file CharsetEncoder.java * @package com.hoo.mina.code * @project ApacheMiNa * @blog http://blog.csdn.net/IBM_hoojo * @email [email protected] * @version 1.0 */ public class CharsetEncoder implements ProtocolEncoder { private final static Logger log = Logger.getLogger(CharsetEncoder.class); private final static Charset charset = Charset.forName("UTF-8"); @Override public void dispose(IoSession session) throws Exception { log.info("#############dispose############"); } @Override public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception { log.info("#############字符编码############"); IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true); buff.putString(message.toString(), charset.newEncoder()); // put 当前系统默认换行符 // buff.putString(LineDelimiter.DEFAULT.getValue(), charset.newEncoder()); // 为下一次读取数据做准备 buff.flip(); out.write(buff); } }
部分代码(直接拷贝到java web项目下)