Java Netty和BoneCP/Basic Socket Server的更多用户
免责声明-我不是Java程序员。很可能我需要根据任何建议做家庭作业,但我很乐意这么做:) 也就是说,我编写了一个完整的数据库支持的socket服务器,它在我的小测试中工作得很好,现在我正准备进行初始发布。因为我对Java/Netty/BoneCP不太了解,所以我不知道我是否在某个地方犯了一个根本性的错误,在我的服务器还没出来之前就已经对它造成了伤害 例如,我不知道执行者小组到底做了什么,我应该使用什么数字。是否可以将BoneCP作为一个单例实现,是否真的需要为每个数据库查询提供所有这些try/catch?等等 我试图将我的整个服务器简化为一个基本示例,它的运行方式与真实的服务器相同(我在文本中剥离了所有内容,没有在java中进行测试,因此请原谅由此产生的语法错误) 基本思想是,客户机可以连接,与服务器交换消息,断开其他客户机的连接,并无限期地保持连接,直到他们选择或被迫断开连接。(客户端将每分钟发送ping消息以保持连接处于活动状态) 除了取消测试这个示例之外,唯一的主要区别是clientID的设置方式(安全地假设每个连接的客户机的clientID确实是唯一的),以及在检查值等方面有更多的业务逻辑 底线-可以做些什么来改进它,使它能够处理尽可能多的并发用户吗?谢谢Java Netty和BoneCP/Basic Socket Server的更多用户,java,netty,bonecp,Java,Netty,Bonecp,免责声明-我不是Java程序员。很可能我需要根据任何建议做家庭作业,但我很乐意这么做:) 也就是说,我编写了一个完整的数据库支持的socket服务器,它在我的小测试中工作得很好,现在我正准备进行初始发布。因为我对Java/Netty/BoneCP不太了解,所以我不知道我是否在某个地方犯了一个根本性的错误,在我的服务器还没出来之前就已经对它造成了伤害 例如,我不知道执行者小组到底做了什么,我应该使用什么数字。是否可以将BoneCP作为一个单例实现,是否真的需要为每个数据库查询提供所有这些try/c
//MAIN
公共类主服务器{
公共静态void main(字符串[]args){
EDGECONTROLER EDGECONTROLER=新EDGECONTROLER();
edgeController.connect();
}
}
//边缘控制器
公共类边缘控制器{
public void connect()引发异常{
ServerBootstrap b=新的ServerBootstrap();
渠道f;
试一试{
b、 组(新的NioEventLoopGroup(),新的NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.localAddress(9100)
.childOption(ChannelOption.TCP_NODELAY,true)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(新的EdgeInitializer(新的DefaultEventExecutorGroup(10));
//启动服务器。
f=b.bind().sync();
//等待服务器套接字关闭。
f、 通道().closeFuture().sync();
}最后{//还不太确定怎么到这里……但没关系
//关闭所有事件循环以终止所有线程。
b、 关机();
}
}
}
//边缘起爆器
公共类EdgeInitializer扩展了通道初始值设定项{
私人事件执行组执行组;
公共边缘初始化器(EventExecutorGroup\u executorGroup){
executorGroup=_executorGroup;
}
@凌驾
public void initChannel(SocketChannel ch)引发异常{
ChannelPipeline=通道管道();
addLast(“idleStateHandler”,新的idleStateHandler(200,0,0));
addLast(“idleStateEventHandler”,newedgeidlehandler());
pipeline.addLast(“framer”,新的DelimiterBasedFrameDecoder(8192,Delimiters.nulDelimiter());
pipeline.addLast(“解码器”,新的StringDecoder(CharsetUtil.UTF_8));
addLast(“编码器”,新的StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(this.executorGroup,“handler”,newedgehandler());
}
}
//埃吉德勒汉德勒
公共类EdgeileHandler扩展了ChannelHandlerAdapter{
私有静态最终记录器Logger=Logger.getLogger(EdgeIdleHandler.class.getName());
@凌驾
public void userEventTriggered(ChannelHandlerContext ctx,Object evt)引发异常{
if(IdleStateEvent的evt实例){
ctx.close();
}
}
私有无效跟踪(字符串msg){
logger.log(Level.INFO,msg);
}
}
//数据库控制器
公共枚举数据库控制器{
实例;
私有BoneCP connectionPool=null;
私有BoneCPConfig connectionPoolConfig=null;
公共布尔设置池(){
布尔ret=真;
试一试{
Class.forName(“com.mysql.jdbc.Driver”);
connectionPoolConfig=new-BoneCPConfig();
connectionPoolConfig.setJdbcUrl(“jdbc:mysql://”+DB_主机+:“+DB_端口+”/“+DB_名称”);
connectionPoolConfig.setUsername(DB_用户);
connectionPoolConfig.setPassword(DB_PASS);
试一试{
connectionPool=新的BoneCP(connectionPoolConfig);
}catch(SQLException-ex){
ret=假;
}
}捕获(ClassNotFoundException ex){
ret=假;
}
返回(ret);
}
公共连接getConnection(){
连接网;
试一试{
ret=connectionPool.getConnection();
}catch(SQLException-ex){
ret=null;
}
返回(ret);
}
}
//边缘处理工
公共类EdgeHandler扩展ChannelInboundMessageHandlerAdapter{
私有最终字符集Charset_UTF8=Charset.forName(“UTF-8”);
私人长客户;
静态最终通道组通道=新的DefaultChannelGroup();
@凌驾
公共无效channelActive(ChannelHandlerContext ctx)引发异常{
连接dbConnection=null;
Statement=null;
ResultSet ResultSet=null;
字符串查询;
布尔值okToPlay=false;
//检查ID#1的状态是否为真
试一试{
query=“从`ServerTable`中选择`Status`,其中`ID`=1”;
dbConnection=DBController.INSTANCE.getConnection();
statement=dbConnection.createStatement();
resultSet=语句.executeQuery(查询);
if(resultSet.first()){
if(resultSet.getInt(“状态”)>0){
okToPlay=true;
//MAIN
public class MainServer {
public static void main(String[] args) {
EdgeController edgeController = new EdgeController();
edgeController.connect();
}
}
//EdgeController
public class EdgeController {
public void connect() throws Exception {
ServerBootstrap b = new ServerBootstrap();
ChannelFuture f;
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.localAddress(9100)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new EdgeInitializer(new DefaultEventExecutorGroup(10)));
// Start the server.
f = b.bind().sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally { //Not quite sure how to get here yet... but no matter
// Shut down all event loops to terminate all threads.
b.shutdown();
}
}
}
//EdgeInitializer
public class EdgeInitializer extends ChannelInitializer<SocketChannel> {
private EventExecutorGroup executorGroup;
public EdgeInitializer(EventExecutorGroup _executorGroup) {
executorGroup = _executorGroup;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("idleStateHandler", new IdleStateHandler(200,0,0));
pipeline.addLast("idleStateEventHandler", new EdgeIdleHandler());
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.nulDelimiter()));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(this.executorGroup, "handler", new EdgeHandler());
}
}
//EdgeIdleHandler
public class EdgeIdleHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger( EdgeIdleHandler.class.getName());
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception{
if(evt instanceof IdleStateEvent) {
ctx.close();
}
}
private void trace(String msg) {
logger.log(Level.INFO, msg);
}
}
//DBController
public enum DBController {
INSTANCE;
private BoneCP connectionPool = null;
private BoneCPConfig connectionPoolConfig = null;
public boolean setupPool() {
boolean ret = true;
try {
Class.forName("com.mysql.jdbc.Driver");
connectionPoolConfig = new BoneCPConfig();
connectionPoolConfig.setJdbcUrl("jdbc:mysql://" + DB_HOST + ":" + DB_PORT + "/" + DB_NAME);
connectionPoolConfig.setUsername(DB_USER);
connectionPoolConfig.setPassword(DB_PASS);
try {
connectionPool = new BoneCP(connectionPoolConfig);
} catch(SQLException ex) {
ret = false;
}
} catch(ClassNotFoundException ex) {
ret = false;
}
return(ret);
}
public Connection getConnection() {
Connection ret;
try {
ret = connectionPool.getConnection();
} catch(SQLException ex) {
ret = null;
}
return(ret);
}
}
//EdgeHandler
public class EdgeHandler extends ChannelInboundMessageHandlerAdapter<String> {
private final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
private long clientID;
static final ChannelGroup channels = new DefaultChannelGroup();
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Connection dbConnection = null;
Statement statement = null;
ResultSet resultSet = null;
String query;
Boolean okToPlay = false;
//Check if status for ID #1 is true
try {
query = "SELECT `Status` FROM `ServerTable` WHERE `ID` = 1";
dbConnection = DBController.INSTANCE.getConnection();
statement = dbConnection.createStatement();
resultSet = statement.executeQuery(query);
if (resultSet.first()) {
if (resultSet.getInt("Status") > 0) {
okToPlay = true;
}
}
} catch (SQLException ex) {
okToPlay = false;
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException logOrIgnore) {
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException logOrIgnore) {
}
}
if (dbConnection != null) {
try {
dbConnection.close();
} catch (SQLException logOrIgnore) {
}
}
}
if (okToPlay) {
//clientID = setClientID();
sendCommand(ctx, "HELLO", "WORLD");
} else {
sendErrorAndClose(ctx, "CLOSED");
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
channels.remove(ctx.channel());
}
@Override
public void messageReceived(ChannelHandlerContext ctx, String request) throws Exception {
// Generate and write a response.
String[] segments_whitespace;
String command, command_args;
if (request.length() > 0) {
segments_whitespace = request.split("\\s+");
if (segments_whitespace.length > 1) {
command = segments_whitespace[0];
command_args = segments_whitespace[1];
if (command.length() > 0 && command_args.length() > 0) {
switch (command) {
case "HOWDY": processHowdy(ctx, command_args); break;
default: break;
}
}
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
TraceUtils.severe("Unexpected exception from downstream - " + cause.toString());
ctx.close();
}
/* */
/* STATES - / CLIENT SETUP */
/* */
private void processHowdy(ChannelHandlerContext ctx, String howdyTo) {
Connection dbConnection = null;
Statement statement = null;
ResultSet resultSet = null;
String replyBack = null;
try {
dbConnection = DBController.INSTANCE.getConnection();
statement = dbConnection.createStatement();
resultSet = statement.executeQuery("SELECT `to` FROM `ServerTable` WHERE `To`='" + howdyTo + "'");
if (resultSet.first()) {
replyBack = "you!";
}
} catch (SQLException ex) {
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException logOrIgnore) {
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException logOrIgnore) {
}
}
if (dbConnection != null) {
try {
dbConnection.close();
} catch (SQLException logOrIgnore) {
}
}
}
if (replyBack != null) {
sendCommand(ctx, "HOWDY", replyBack);
} else {
sendErrorAndClose(ctx, "ERROR");
}
}
private boolean closePeer(ChannelHandlerContext ctx, long peerClientID) {
boolean success = false;
ChannelFuture future;
for (Channel c : channels) {
if (c != ctx.channel()) {
if (c.pipeline().get(EdgeHandler.class).receiveClose(c, peerClientID)) {
success = true;
break;
}
}
}
return (success);
}
public boolean receiveClose(Channel thisChannel, long remoteClientID) {
ChannelFuture future;
boolean didclose = false;
long thisClientID = (clientID == null ? 0 : clientID);
if (remoteClientID == thisClientID) {
future = thisChannel.write("CLOSED BY PEER" + '\n');
future.addListener(ChannelFutureListener.CLOSE);
didclose = true;
}
return (didclose);
}
private ChannelFuture sendCommand(ChannelHandlerContext ctx, String cmd, String outgoingCommandArgs) {
return (ctx.write(cmd + " " + outgoingCommandArgs + '\n'));
}
private ChannelFuture sendErrorAndClose(ChannelHandlerContext ctx, String error_args) {
ChannelFuture future = sendCommand(ctx, "ERROR", error_args);
future.addListener(ChannelFutureListener.CLOSE);
return (future);
}
}