我创建了一个NIO服务器,它同时在一个端口接收4000个设备数据。每个设备有30秒的间隔在服务器上发送数据。我的代码在1或2秒内将数据插入db到600到1000条记录。
数据从另一个.net应用程序服务器转发到我的nio服务器。
有时我在.NET应用程序的控制台上遇到以下错误:
“连接尝试失败,因为连接方没有 一段时间后,或建立连接后适当的回应 失败,因为连接的主机无法响应 52.74.204.124:6000"
NIO服务器代码如下。
public class ServerSockets {
public static void main(String[] args) throws IOException
{
int ports[] = new int[] {6000};
Selector selector =Selector.open();
// loop through each port in our list and bind it to a ServerSocketChannel
for (int port : ports) {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(port));
// selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
Set keys=null;
SelectionKey key=null;
String REQUEST_DATA = null;
String remoteAddress = null;
String device_ip = null;
String device_port = null;
//check for all port whom ready to send data
while (true) {
try {
// loop over all the sockets that are ready for some activity
while (selector.select()>0) {
keys= selector.selectedKeys();
Iterator i = keys.iterator();
while (i.hasNext()) {
key = (SelectionKey)i.next();
if (key.isAcceptable()) {
// this means that a new client has hit the port our main
// socket is listening on, so we need to accept the connection
// and add the new client socket to our select pool for reading
// a command later
//System.out.println("Accepting connection!");
//FETCH DB DATA
//DatabaseActivity databaseActivity = new DatabaseActivity();
//databaseActivity.db_mongoFetch("jj_tracking");
// this will be the ServerSocketChannel we initially registered
// with the selector in main()
ServerSocketChannel sch = (ServerSocketChannel)key.channel();
SocketChannel ch = sch.accept();
ch.configureBlocking(false);
ch.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// one of our client sockets has received a command and
// we're now ready to read it in
SocketChannel ch=null;
try
{
//System.out.println("Accepting command!");
ch = (SocketChannel)key.channel();
remoteAddress = String.valueOf(ch.getRemoteAddress());
//System.out.println("LOCAL ADDRESS 5 ---> "+remoteAddress);
if(remoteAddress !=null && remoteAddress.length() > 0){
String[] remoteAddressArr = remoteAddress.split(":");
if(remoteAddressArr.length > 0){
device_ip = remoteAddressArr[0].substring(1);
device_port = remoteAddressArr[1];
}
}
ByteBuffer buf = ByteBuffer.allocate(8024);
ch.read(buf);
if(buf.position()>0){
buf.flip();
System.out.println("-----------------------------");
System.out.println("REQEST_STRING => "+new String(buf.array()));
System.out.print("HEX_STRING => "+convertToHex(buf.array(),buf.limit())+"\n\n");
//String REQUEST_DATA_STRING = new String(buf.array());
//System.out.println("ORIGNAL REQUEST STRING => "+REQUEST_DATA_STRING);
/**
*
* CONDITION FOR TK06 [ NEW ALTRA ]
* FETCH IMEI NUMBER THAT ATTACHED WITH REQUEST STRING
* SEPERATOR "~##~"
*
* */
/*if(REQUEST_DATA_STRING.contains("~##~")){
String[] REQUEST_DATA_ARR = REQUEST_DATA_STRING.split("~##~");
String imei_number = REQUEST_DATA_ARR[0].trim();
//REQUEST_DATA = new String(convertToHex(String.valueOf(REQUEST_DATA_ARR[1]).getBytes(),buf.limit())).trim();
REQUEST_DATA = REQUEST_DATA +"~@@@~"+ imei_number;
System.out.println("PROCESSED STRING => "+REQUEST_DATA);
}else{// NORMAL CASE FOR OTHER DEVICE
//ACTUAL CODE
REQUEST_DATA = new String(convertToHex(buf.array(),buf.limit())).trim();
//FOR TESTNG ON ABHISHEK SYS
//REQUEST_DATA = new String(buf.array()).trim();
}*/
// OLD CODE
//ACTUAL CODE
REQUEST_DATA = new String(convertToHex(buf.array(),buf.limit())).trim();
//FOR TESTNG ON ABHISHEK SYS
//REQUEST_DATA = new String(buf.array()).trim();
if(REQUEST_DATA != null && !REQUEST_DATA.isEmpty()){
ProcessRequest processRequest = new ProcessRequest();
processRequest.processRequestString(REQUEST_DATA, device_ip, device_port);
}
}else{
key.channel().close();
ch.close();
}
}catch(IOException E){
key.cancel();
ch.close();
}
/* Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
CharBuffer cbuf = decoder.decode(buf);
System.out.print(cbuf.toString());*/
// re-register this socket with the selector, this time
// for writing since we'll want to write something to it
// on the next go-around
// ch.register(selector, SelectionKey.OP_READ);
}
i.remove();
}
}
} catch (IOException e) {
System.out.println("Error in poll loop");
System.out.println();
e.printStackTrace();
System.exit(1);
}
}
}
答案 0 :(得分:0)
我想问题是这个应用程序的可伸缩性。代码处理单线程中的所有内容(主线程也处理新连接的接受)。
如果传入数据的处理花费了太多时间,则会导致等待接受其连接的客户端的长队列,并且底层操作系统可能会拒绝进一步的请求。
我建议将nio2与异步完成处理程序或Apache Mina或Netty等高级框架一起使用。
PS:另外,请注意上面的代码有更多的问题,特别是管理缓冲区的读取操作 - 它需要以某种方式检查客户端是否已经发送了可能被网络层碎片化的所有数据。使用http://docs.oracle.com/javase/8/docs/api/java/nio/channels/AsynchronousSocketChannel.html,您可以确保重复读取,直到您收到完整的消息。