最近用java开发了一个游戏服务,老板要求采用Epoll模式.现在项目已做完,把实现epoll的经验和大伙共享一下:
关于epoll的介绍这里就不多说,网上一大把.
1.从resion的官网上下载resin-3.0.22版本(里面就有一个例子,我就是用这例子改改而以)
2.创建ServerProtocol类
package com.wd.dzpk.SocketServer;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Logger;
import com.caucho.server.connection.Connection;
import com.caucho.server.port.Protocol;
import com.caucho.util.L10N;
/**
*
*/
public class ServerProtocol extends Protocol {
static protected final Logger log = Logger.getLogger(ServerProtocol.class
.getName());
static final L10N L = new L10N(ServerProtocol.class);
private String _protocolName = "magic8ball";
/**
* Construct.
*/
public ServerProtocol() {
}
/**
* Returns the protocol name.
*/
public String getProtocolName() {
return _protocolName;
}
/**
* Sets the protocol name.
*/
public void setProtocolName(String name) {
_protocolName = name;
}
/**
* Create a Magic8BallRequest object for the new thread.
*/
public MyServerRequest createRequest(Connection conn) {
return new MyServerRequest(this, conn);
}
}
关键是MyServerRequest 方法(),用于初始化
3.创建MyServerRequest 类
package com.wd.dzpk.SocketServer;
/**
*
* TODO 创建和管理消息类
*
*/
import java.io.IOException;
import com.caucho.server.connection.Connection;
import com.caucho.server.port.ServerRequest;
import com.caucho.vfs.ReadStream;
import com.caucho.vfs.WriteStream;
import com.wd.dzpk.util.Constant;
import com.wd.dzpk.util.Log;
/**
* Protocol specific information for each request. An instance of this object
* may be reused to reduce memory allocations.
*/
public class MyServerRequest implements ServerRequest {
// 连接
Connection _conn;
ServerProtocol _protocol;
Parser _parser = new Parser();
Magic8Ball _magic8ball = new Magic8Ball();
/**
* 在收连接请求,交给此方法处理所有消息
*
* @param ServerProtocol
* @param Connection
* @return void
*/
public MyServerRequest(ServerProtocol protocol, Connection conn) {
_protocol = protocol;
_conn = conn;
}
/**
* Initialize the connection. At this point, the current thread is the
* connection thread.
*/
public void init() {
}
/**
* Handle a new connection. The controlling Server may call handleRequest
* again after the connection completes, so the implementation must
* initialize any variables for each connection.
*/
public boolean handleRequest() throws IOException {
Log.debugLog("收到" + _conn.getRemoteHost() + "的请求");
ReadStream readStream = _conn.getReadStream();
WriteStream writeStream = _conn.getWriteStream();
try {
_parser.init(readStream, writeStream);
AbstractCommand cmd = null;
do {
cmd = _parser.nextCommand();
// 如果是第一条消息,将连接和用户ID进行绑定保存
if (null != cmd) {
if (cmd.getIsFirstMsg()) {
ConObj conObj = new ConObj();
conObj.setConn(_conn);
conObj.setUserId(cmd.getUserId());
// 保存到系统常量中,供全局使用
Constant.AllConnList.add(conObj);
Log.debugLog("收到第一条消息,将连接对象进行保存.用户ID为:"
+ cmd.getUserId());
} else if (cmd.getIsExitMsg()) {
// 从连接列表删除相应的连接
for (int i = 0; i < Constant.AllConnList.size(); i++) {
if (cmd.getUserId()
.equals(
((ConObj) Constant.AllConnList
.get(i)).userId)) {
Constant.AllConnList.remove(i);
// 付值为null,会关闭与客户端的连接
cmd = null;
break;
}
}
Log.debugLog("用户ID为:" + cmd.getUserId()
+ "客户端关闭了,删除连接成功");
}
}
} while (null != cmd);
} catch (Throwable e) {
Log.warningLog("系统出错,原因:" + e.getMessage());
}
return false;
}
/*
* (non-Javadoc)
*
* @see com.caucho.server.port.ServerRequest#isWaitForRead()
*/
public boolean isWaitForRead() {
// TODO Auto-generated method stub
return false;
}
/*
* (non-Javadoc)
*
* @see com.caucho.server.port.ServerRequest#protocolCloseEvent()
*/
public void protocolCloseEvent() {
// TODO Auto-generated method stub
}
}
4.配置resin-3.0.22/conf/resin.conf,在resion启动时,会自动去调用ServerProtocol类来初始化
打开resion.conf文件,找到<server>元素.插入以下代码
<port id='' host='*' port='13000'>
<protocol resin:type="com.wd.dzpk.SocketServer.ServerProtocol"/>
</port>
如下:
<server>
<port id='' host='*' port='13000'>
<protocol resin:type="com.wd.dzpk.SocketServer.ServerProtocol"/>
</port>
<!-- adds all .jar files under the resin/lib directory -->
<class-loader>
<tree-loader path="${resin.home}/lib"/>
<tree-loader path="${server.root}/lib"/>
</class-loader>
就这么简单,如果需要源码,可以发邮件给我.