Подумайте об этом, у вас есть карта сокетов, и каждый раз, когда сообщение поступает на сервер, вы получаете сообщение и связанный сокет!
эта операция выполняется с ОС (linux, windows, unix, ma c -OS, ...) ядро!
, поэтому вы можете обрабатывать миллион соединений только в одном потоке!
мы называем это None-Blocking сокеты , что означает, что они никогда не блокируют ваш поток для чтения или записи или любой другой операции, такой как accept, и ...!
java имеет пакет для обработки этого! java .nio. *
как это работает?
- Поток для обработки операций ввода-вывода
- Селектор для выбора, какие сокеты работают и какой тип операции
- ByteBuffer для обработки чтения и записи вместо использования socket.stream в blocking-socket
также можно использовать несколько потоков и селекторов (каждый селектор имеет свой собственный поток)
посмотрите на этот пример:
NoneBlockingServer. java:
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class NoneBlockingServer {
public static void main(String[] args) throws Exception
{
runServer("localhost" , 5050);
}
private final static void runServer(String host , int port)throws Exception {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(host, port));
serverSocketChannel.configureBlocking(false); //config to be a none-blocking serve-socket
SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//register to selector for operation ACCEPT !
//also you can use selectionKey for some other stuffs !
while (true) {
int numberOfReadSockets = selector.select();
//it will wait until a socket(s) be ready for some io operation
//or other threads call selector.wakeup()
if(numberOfReadSockets==0){
//maybe selector.wakeup() called
//do some sync operations here !
continue; // continue selecting !
}
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext())
{
SelectionKey key = keys.next();
keys.remove(); //remove selected key from current selection !
//handle selected key
if(key.isValid() && key.isReadable())
{
//it means this socket is valid and has data to read
SocketChannel socketChannel =
(SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(100); // allocate 100 bytes for buffer
//maybe you must use an allocated buffer for each connection
// instead of allocate for each operation
int read = socketChannel.read(buffer);
if(read<0)
{
//need to close channel !
socketChannel.close(); // explicitly remove from selector
System.out.println("CONNECTION CLOSED");
continue; //socket closed and other operations will skip
}else
{
buffer.flip(); // you need to learn work with ByteBuffers
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
//maybe convert it to String
String msg = new String(bytes);
//use msg !
System.out.println("MESSAGE : "+msg);
key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);
//set interestOps to WRIT and READ to write hello back message !
key.attach(ByteBuffer.wrap("Hello Client !".getBytes("UTF-8")));
//wrap a array of bytes using wrap and attach it to selectionKey
}
}
if(key.isValid() && key.isWritable())
{
//it means this socket is valid and have space to write data !
SocketChannel socketChannel =
(SocketChannel) key.channel();
//you must represent data you want to write to this socket
//maybe attached to selection key !
ByteBuffer dataToWrite = (ByteBuffer) key.attachment();
//key.attachment here to help u have some meta data about each socket
//use it smart !
int write = socketChannel.write(dataToWrite);
if(write<0)
{
//so means some error occurs better to close it !
socketChannel.close();
System.out.println("CONNECTION CLOSED !"); //log
continue;//as socket closed we will skip next operations !
}else if(!dataToWrite.hasRemaining())
{
//so all data putted to buffer !
key.interestOps(SelectionKey.OP_READ); // just need to read !
}
}
if(key.isValid() && key.isAcceptable())
{
ServerSocketChannel server =
(ServerSocketChannel) key.channel();//just server channels has accept operation
SocketChannel socketChannel = server.accept(); //accept it !
socketChannel.configureBlocking(false); // config none-blocking mode
socketChannel.register(selector , SelectionKey.OP_READ);
//also you can register for multiple operation using | operation
//for example register for both read and write SelectionKey.READ|SelectionKey.WRITE
//also you can change is late using key.interestOps(int ops)
System.out.println("NEW CONNECTION"); //log
}
//there is another type of key, key.isConnectable()
//google it !
}
}
}
}
и вот BlockingClient. java:
import java.net.InetSocketAddress;
import java.net.Socket;
public class BlockingClient {
//using blocking sockets !
public static void main(String[] args)throws Exception
{
Socket socket = new Socket();
socket.connect(new InetSocketAddress("localhost" , 5050));
socket.getOutputStream()
.write("Hello Server".getBytes("UTF-8"));
byte[] buffer = new byte[100];
int len = socket.getInputStream().read(buffer);
System.out.println(new String(buffer , 0 , len , "UTF-8"));
socket.close();
}
}
в этом примере мы отправляем сообщение Hello Server от клиента блокировки на сервер без блокировки, и сервер отвечает на сообщение Hello Client!
просто запустите!
Удачи