[英]Java, how manage threads to read socket (websocket)?
I have a WebSocket server.我有一个 WebSocket 服务器。
my server create a new thread for handle a new connection.the thread is live until websocket break.我的服务器创建一个新线程来处理新连接。该线程一直有效,直到 websocket 中断。
my problem: for 1_000_000 connections i need 1_000_000 threads.我的问题:对于 1_000_000 个连接,我需要 1_000_000 个线程。 how i can handle many websockets by a thread?我如何通过一个线程处理多个 websocket? without wait?无需等待?
ServerSocket server;
private ExecutorService executor = new ThreadPoolExecutor(1_000_000 , 1_000_000 , 7, TimeUnit.SECONDS, queue, threadFactory);
try
{
server = new ServerSocket(port);
}
catch (IOException e) {}
while (true)
{
Socket client = null;
try
{
client = server.accept();
Runnable r = new Runnable()
{
run()
{
// this is simple, original is complete WebSocket imp
client.getInputStream().read();
}
};
executor.execute(r);
}
catch (IOException e) {}
}
Your concept is wrong.你的概念是错误的。 You should not start a new thread every few milliseconds because that will slow down your system a lot.您不应该每隔几毫秒启动一个新线程,因为这会大大降低您的系统速度。 Also you cannot have 1 Million connections open at the same time.此外,您不能同时打开 100 万个连接。 No normal operating system would allow that.任何正常的操作系统都不允许这样做。
Rather than that, normal web servers run a maximum number of threads (eg 100 on an average server) which process the incoming requests sequentially.与此不同的是,普通的 Web 服务器运行最大数量的线程(例如,平均服务器上 100 个)依次处理传入的请求。
Think about this you have a map of sockets and every time a message received to server you will get message and related socket !想想看,您有一个套接字映射,每次收到服务器的消息时,您都会收到消息和相关的套接字!
this operation done with OS(linux , windows , unix , mac-OS , ...) kernel !这个操作是用 OS(linux , windows , unix , mac-OS , ...) 内核完成的!
so you can handle a million connection just in one thread !所以你可以在一个线程中处理一百万个连接!
we call this None-Blocking sockets which means they never block your thread to read or write or any other operation such as accept and ... !我们称之为无阻塞套接字,这意味着它们永远不会阻止您的线程读取或写入或任何其他操作,例如接受和...!
java has a package to handle this ! java有一个包来处理这个! java.nio.* java.nio.*
how it's work ?它是如何工作的?
also you can use multiple thread and selectors (each selector has its own thread)您也可以使用多个线程和选择器(每个选择器都有自己的线程)
look at this example :看看这个例子:
NoneBlockingServer.java : 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 !
}
}
}
}
and here is BlockingClient.java :这是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();
}
}
at this example we send Hello Server message from Blocking Client to None-Blocking Server and server will response Hello Client message !在这个例子中,我们将 Hello Server 消息从 Blocking Client 发送到 None-Blocking Server,服务器将响应 Hello Client 消息!
just run !赶紧跑 !
Good luck祝你好运
A tempting thought is "don't use java".一个诱人的想法是“不要使用java”。 Java has terrible green thread support but golang and erlang are built on green threading so they do it very well. Java 对绿色线程的支持很糟糕,但是 golang 和 erlang 是建立在绿色线程之上的,所以它们做得很好。
The java way seems to be worker pools. java方式似乎是工作池。 So you create an Executor pool (see java.util.concurrent), decide how many workers you want for a given number of connections, then pass connections to workers via a queue.因此,您创建了一个 Executor 池(请参阅 java.util.concurrent),确定给定数量的连接需要多少个工作线程,然后通过队列将连接传递给工作线程。 A worker then has to iterate over its set of connections deciding to process each or yield.然后,工作人员必须迭代其连接集,决定处理每个连接还是让步。
Your number of live tcp connections is hard capped at about 2^16 (65_536: number of available ports) but the system is unlikely to be performant if you have that many connections anyway.您的实时 tcp 连接数严格限制在大约 2^16(65_536:可用端口数),但如果您有那么多连接,系统就不太可能具有高性能。 Most systems can't maintain performance for more than ~200 persistent connections.大多数系统无法维持超过 200 个持久连接的性能。 If you can far exceed that number I would assume your system isn't doing enough per connection to really justify the use of web sockets, but I'm only guessing.如果你可以远远超过这个数字,我会假设你的系统每个连接做的不够,无法真正证明使用网络套接字是合理的,但我只是猜测。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.