Features of Http Protocol
1. Simplex communication, the server cannot push information to the client
2. Request-response mode
3 Stateless
Due to the above characteristics of http, the traditional mode Web system works in the way that the client sends a request and the server responds. This method does not meet the needs of many real-world applications, such as:
- Monitoring system: background hardware hot swap, LED, temperature, voltage changes;
- Instant messaging system: other users log in and send information;
- Real-time quotation system: the content of the background database changes;
These applications all require that the server can transmit updated information to the client in real time without the client making a request. There are some solutions for "server push" technology in real applications. This article divides these solutions into two categories: one requires installing plug-ins on the browser side, transmitting information based on sockets, or using RMI and CORBA to make remote calls; The other type does not require the browser to install any plug-ins and is based on HTTP long connections.
When applying "server push" to a web program, the first consideration is how to receive and process information on the browser with limited functions:
- How the client receives and processes information, whether it needs to use sockets or use remote calls. Whether the client presents to the user an HTML page or a Java applet or Flash window. If you use sockets and remote calls, how to modify the display of HTML in combination with JavaScript.
- The information format of the communication between the client and the server, and what kind of error handling mechanism is adopted.
- Whether the client needs to support different types of browsers such as IE and Firefox, and whether it needs to support both Windows and Linux platforms.
Comet
One is to control the client's page to continuously make ajax requests, which should be well implemented. js timer can be implemented, and each request will respond to the client if there is updated data on the server side. However, this will cause serious pressure on the server. If there are too many online users, which server can bear the request every one or two seconds, this is definitely not realistic, or it is the most helpless way to achieve it.
So comet appeared. Comet technology is a general term for server push technology, but it is not a specific implementation method. Below I will talk about two implementation methods, which are based on the implementation of HTTP long connections.
The first method is called long-polling, which also uses ajax. To put it simply, the client sends a request using ajax, and the server will definitely open a thread, which will monitor the data to be requested from time to time. Whether there is a change, if there is a change, output the latest message to the client and close the link. After the client receives the message processing, it requests the server again. This cycle is repeated, so it is called long polling. One is naturally much better, it does not require constant ajax requests from the client, relieves a certain pressure on the server, and can be regarded as real-time.
The main difference between polling and long polling is how long the server takes to respond. Long polling typically maintains a connection for an extended period of time—usually seconds, but could be a minute or more. When an event occurs on the server, the response is sent and immediately closed, and polling restarts immediately .
The advantage of long polling over normal polling is that data is sent from the server to the client as soon as it is available. The request may wait a long time without any data being returned, but as soon as there is new data, it will be sent to the client. So there is no delay. If you've ever used a web-based chat program, or any program that claims to be "real-time", it most likely uses this technology
The other is the streaming method, which is similar to the long polling method, except that the streaming method is that after the client requests the server and establishes a link, the server will never close the link (until timeout, power failure or Other special cases) output to the client every time there is data, unlike long polling, which has to close the connection after each output to the client
Comet implementation bottleneck solution - server servlet thread blocking problem
NIO原理
IO |
NIO |
---|---|
Core differences: | Core differences: |
Stream oriented processing | Uses buffers |
Blocking in processing | Non blocking in processing |
Good for: | Good for: |
High data volume with low simultaneous open file descriptor counts (eg: less client connections with more data chunks per connection) |
Less data volume with high simultaneous open file descriptor counts (eg: More connections with smaller / infrequent “chunks” of data) |
A quick glance at the summary of the Java NIO API reveals to us the core abstractions one should be familiar with when working with Java NIO. These are:
- Buffers : A container to hold data for the purposes of reading and or writing.
- Channels : An abstraction for dealing with an open connection to some component that is performing some kind of IO operation at a hardware level.
- Charsets : Contains charsets, decoders and encoders for translating between bytes and unicode.
- Selectors : A means to work with multiple channels via one abstraction.
Streams versus blocks
The most important distinction between the original I/O library (found in java.io.*
) and NIO has to do with how data is packaged and transmitted. As previously mentioned, original I/O deals with data in streams, whereas NIO deals with data in blocks.
A stream-oriented I/O system deals with data one byte at a time. An input stream produces one byte of data, and an output stream consumes one byte of data. It is very easy to create filters for streamed data. It is also relatively simply to chain several filters together so that each one does its part in what amounts to a single, sophisticated processing mechanism. On the flip side, stream-oriented I/O is often rather slow.
A block-oriented I/O system deals with data in blocks. Each operation produces or consumes a block of data in one step. Processing data by the block can be much faster than processing it by the (streamed) byte. But block-oriented I/O lacks some of the elegance and simplicity of stream-oriented I/O.
Three easy steps
Our first step is to get a channel. We get the channel from the FileInputStream
:
1
2
|
FileInputStream fin = new FileInputStream( "readandshow.txt" );
FileChannel fc = fin.getChannel();-------
IO是单向的,input或者output,在建立连接后,通过创建channel获取一个双向的通道,channel是双向的
|
The next step is to create a buffer:
1
|
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
|
And, finally, we need to read from the channel into the buffer, as shown here:
1
|
fc.read( buffer );
|
Writing to a file
Writing to a file in NIO is similar to reading from one. We start by getting a channel from a FileOutputStream
:
1
2
|
FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" );
FileChannel fc = fout.getChannel();
|
Our next step is to create a buffer and put some data in it -- in this case, the data will be taken from an array called message
which contains the ASCII bytes for the string "Some bytes." (The buffer.flip()
and buffer.put()
calls will be explained later in the tutorial.)
1
2
3
4
5
6
|
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
for (int i=0; i<message.length; ++i) {
buffer.put( message[i] );
}
buffer.flip();
|
Our final step is to write to the buffer:
1
|
fc.write( buffer );
|
如果IO是系统的瓶颈,那么可以利用多线程充分使用cpu资源。
{ ExecutorService executor = Excutors.newFixedThreadPollExecutor(100);//线程池 ServerSocket serverSocket = new ServerSocket(); serverSocket.bind(8088); while(!Thread.currentThread.isInturrupted()){//主线程死循环等待新连接到来 Socket socket = serverSocket.accept(); executor.submit(new ConnectIOnHandler(socket));//为新的连接创建新的线程 } class ConnectIOnHandler extends Thread{ private Socket socket; public ConnectIOnHandler(Socket socket){ this.socket = socket; } public void run(){ while(!Thread.currentThread.isInturrupted()&&!socket.isClosed()){死循环处理读写事件 String someThing = socket.read()....//读取数据 if(someThing!=null){ ......//处理数据 socket.write()....//写数据 } } } }
上面的代码是经典的单连接单线程模型。其实这也是所有使用多线程的本质:利用多核,当IO阻塞系统的时候,可以充分利用CPU的资源。这个模型如果单机线程数1000,其实ok的。不过这个模型主要的问题是严重依赖线程,线程是非常昂贵的资源,因为一个线程大约占用内容512k-1M,而且线程数过大,创建和销毁成本也高,线程之间切换也有一定的成本。
如果面对十万级,百万级连接,传统的BIO模型无能为力。
NIO:利用一个线程管理selector,selector监听多个channel。减少了线程的数据,监听了更多的socket。理论上可以用一个线程处理所有的socket请求
NIO一个重要的特点是:socket主要的读、写、注册和接收函数,在等待就绪阶段都是非阻塞的,真正的I/O操作是同步阻塞的(消耗CPU但性能非常高)