HTML5 y la Web móvil: el tráfico de red

A, Comet- Ajax-basada largo de votación

Definición: El cliente envía una solicitud al servidor Ajax, mantenga servidor de conexión en vivo a petición, no vuelve hasta que una nueva información de respuesta de mensaje y cerrar la conexión, el cliente envía una nueva información de respuesta después de su petición al servidor.

  1. El servidor se bloquea hasta que los tiempos de solicitud o de la cesión de datos de retorno.
  2. Del lado del cliente mensaje de respuesta de procesamiento de la función JavaScript devuelto por el servidor una vez finalizado el proceso, la solicitud de nuevo, para volver a establecer la conexión.
  3. Cuando el cliente procesa los datos recibidos, re-establecer la conexión, el servidor puede tener nuevos datos llegan; esta información se almacenará hasta que el cliente para restablecer la conexión, el cliente va a terminar una vez que el servidor actual para recuperar toda la información en el lado del servidor.

Ventajas: no se solicitan con frecuencia mensaje sin un caso, un pequeño consumo de recursos.

Inconveniente : el servidor mantenga la conexión consumirá recursos, para asegurar que los datos no se orden, difícil de manejar y mantener regresó.

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link rel="stylesheet"
	href="http://apps.bdimg.com/libs/jquerymobile/1.4.5/jquery.mobile-1.4.5.min.css">
<!-- 引入 jQuery 库 -->
<script src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.min.js"></script>
<!-- 引入 jQuery Mobile 库 -->
<script
	src="http://apps.bdimg.com/libs/jquerymobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>

<script type="text/javascript">

	$(function() {
		getMsgNum();
	});
	function getMsgNum() {
		$.ajax({
			url : 'JsLongPollingMsgServlet',
			type : 'post',
			dataType : 'json',
			data : {
				"pageMsgNum" : $("#pageMsgNum").val()
			},
			timeout : 5000,
			success : function(data, textStatus) {
				if (data && data.msgNum) {
					//请求成功,刷新数据
					$("#msgNum").html(data.msgNum);
					//这个是用来和后台数据作对比判断是否发生了改变
					$("#pageMsgNum").val(data.msgNum);
				}
				if (textStatus == "success") {
					//成功之后,再发送请求,递归调用
					getMsgNum();
				}
			},
			error : function(XMLHttpRequest, textStatus, errorThrown) {
				if (textStatus == "timeout") {
					//有效时间内没有响应,请求超时,重新发请求
					getMsgNum();
				} else {
					// 其他的错误,如网络错误等
					getMsgNum();
				}
			}
		});
	}
</script>
</head>

<body>
	<div id="page1" data-role="page">
		<div data-role="header">
			<h1>AJAX长轮询</h1>
		</div>
		<div data-role="content">
			<input id="pageMsgNum" name="pageMsgNum" type="hidden" /> 您有<span
				id="msgNum" style="color: red;">0</span>条消息!
		</div>
		<div data-role="footer">
			<h1>CopyRight 2019</h1>
		</div>
	</div>
</body>
</html>


import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class JsLongPollingMsgServlet
 */
@WebServlet("/JsLongPollingMsgServlet")
public class JsLongPollingMsgServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public JsLongPollingMsgServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		ServletContext application = this.getServletContext();
	   List msglist= (List)application.getAttribute("msg");
	   request.setCharacterEncoding("utf-8");

	       PrintWriter out = response.getWriter();
	       String pageMsgNumStr = request.getParameter("pageMsgNum");
	       if(pageMsgNumStr==null || "".equals(pageMsgNumStr)){
	           pageMsgNumStr = "0";
	       }
	       int pageMsgNum = Integer.parseInt(pageMsgNumStr);

	       int num = 0;
	       StringBuffer json = null;
	       while(true){
	           num = msglist.size();
	           //数据发生改变 将数据响应客户端
	           if(num != pageMsgNum){
	               json = new StringBuffer("{");
	               json.append("\"msgNum\":"+num);
	               json.append("}");
	               break;
	           }else{
	               //没有新的数据 保持住连接
	               try {
	                   Thread.sleep(1000);
	               } catch (InterruptedException e) {
	                   e.printStackTrace();
	               }
	           }
	       }
	       out.write(json.toString());
	       out.close();
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

	
}

Dos, Comet- htmlfile basado en el modo de marco flotante (Streaming) de flujo y

  1. El iframe programa cliente, servidor de iframe no devuelve los datos de la página que se muestra directamente, sino que vuelve a las funciones Javascript de cliente de llamada, como "<script type =" text / javascript "> js_func (" datos desde un servidor " ) </ script>". El servidor devolverá los datos como del lado del cliente pasan los parámetros de función de JavaScript; motor de Javascript del navegador del cliente a cambio de recibir llamadas irán al servidor cuando la ejecución de código JavaScript.
  2. Cada transferencia de datos no se cierra la conexión, la conexión sólo cuando se produce un error de comunicación, dentro o fuera (algunos servidores de seguridad se fijan a menudo demasiado tiempo para cancelar la conexión, el servidor puede establecer un tiempo de espera después de un restablecimiento de conexión del cliente de notificación de tiempo de espera re-establecer la conexión y cerrar la conexión original).
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<ul id="content"></ul>
<form class="form">
<input type="text" placeholder="请输入发送的消息" class="message" id="message"/>
<input type="button" value="发送" id="send" class="connect"/>
<input type="button" value="连接" id="connect" class="connect"/>
</form>
<script>
	var oUl=document.getElementById('content');
	    var oConnect=document.getElementById('connect');
	    var oSend=document.getElementById('send');
	    var oInput=document.getElementById('message');
	    var ws=null;
	    oConnect.onclick=function(){
	        ws=new WebSocket('ws://localhost:3000');
	         ws.onopen=function(){
	             oUl.innerHTML+="<li>客户端已连接</li>";
	         }
	        ws.onmessage=function(evt){
	            oUl.innerHTML+="<li>"+evt.data+"</li>";
	        }
	        ws.onclose=function(){
	            oUl.innerHTML+="<li>客户端已断开连接</li>";
	        };
	        ws.onerror=function(evt){
	            oUl.innerHTML+="<li>"+evt.data+"</li>";
	 
	        };
	    };
	    oSend.onclick=function(){
	        if(ws){
	            ws.send(oInput.value);
	        }
	    }
</script>
</body>
</html>
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Servlet implementation class SetMsg
 */
@WebServlet("/SetMsg")
public class SetMsg extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public SetMsg() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		ServletContext application = this.getServletContext();
		   List msglist= new ArrayList();

		if(application.getAttribute("msg")!=null)
		{
			msglist=(List)application.getAttribute("msg");
		}
		
			
		   msglist.add(request.getParameter("msgstr"));
		   application.setAttribute("msg", msglist);
		   	
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

Tres, SSH

  • SSE y WebSocket efecto similar, son canales de comunicación entre el navegador y el servidor, y el servidor a la información de empuje al navegador establecidos.
  • En general, WebSocket más potente y flexible. Debido a que es un canal dúplex completo, la comunicación bidireccional pueden; SSE es un canal unidireccional, sólo el servidor envía al navegador, debido a que el flujo de información es esencialmente descarga. Si el navegador envía información al servidor, se convierte en otra petición HTTP.
  • SSE ventaja
  1. SSE utilizando el protocolo HTTP, el soporte de software de servidor existente. WebSocket es un acuerdo por separado.
  2. SSE pertenece ligero, simple de usar; un protocolo WebSocket es relativamente compleja.
  3. SSE apoyado por reconexión por defecto, WebSocket necesita su propia aplicación.
  4. SSE generalmente utiliza para texto de transmisión, los datos binarios a codificar después de la transferencia, una transmisión compatibilidad predeterminada WebSocket de datos binarios.
  5. SSE apoyo para este tipo de mensajes personalizados envió.
  6. SSE es adecuado para actualizaciones frecuentes, baja latencia y los datos son de servicio al cliente.

protocolo de comunicación es un protocolo simple basado en texto plano.

servidor de datos SSE envía al navegador, debe ser codificado en texto UTF-8, con el siguiente encabezado HTTP.

Content-Type: text / caso-stream

Cache-Control: no-cache

Conexión: keep-alive

La primera línea de la MIME Content-Type debe especificar el tipo de evento-el vapor .

Cada información de tiempo transmitida desde una pluralidad de composición del mensaje, con \ n \ n separación entre cada mensaje. Cada mensaje interno se compone de filas, cada fila es el siguiente formato.

[Campo]: valor \ n

        tipos de datos , lo que indica que la línea contiene los datos. Las líneas que comienzan con los datos pueden aparecer varias veces. Todas estas líneas son los datos del evento.

Si los datos es largo, se puede dividir en una pluralidad de filas, la última fila \ n \ end n, con los extremos de primera fila con \ n.

       Tipo de lo anterior Identificación del mencionado , según el banco identificador utiliza para declarar un evento, el número equivalente de cada pieza de datos.

       De Tipo de evento , según el banco se utiliza para declarar el tipo de evento. Cuando el navegador recibe los datos, generará los correspondientes tipos de eventos. El valor predeterminado es los eventos de aviso. Navegador puede escuchar a este evento con addEventListener ().

       Tipo de reintento , dijo que el banco se utiliza para declarar navegador tiempo de espera antes de una conexión de nuevo después de la desconexión.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
    <script>
    var eventSource;
        function start() {
            eventSource = new EventSource("HelloServlet");
            eventSource.onmessage = function(event) {
                document.getElementById("foo").innerHTML = event.data;
            };
            eventSource.addEventListener("ms",function(){})
        }
        
        function close(){
          eventSource.close();
        }
    </script>
</head>
<body>
    Time: <span id="foo"></span>
    
    <br><br>
    <button onclick="start()">Start</button>
 <button onclick="close()">Close</button>
</body>
</html>
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    public HelloServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		 // ContentType 必须指定为 text/event-stream
		response.setContentType("text/event-stream");
        // CharacterEncoding 必须指定为 UTF-8
		response.setCharacterEncoding("UTF-8");
        PrintWriter pw = response.getWriter();
 
            // 每次发送的消息必须以\n\n结束

            pw.write("event:ms\n data: " + new Date() + " 这是第1次测试\n\n");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        
        pw.close();
    }
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}
}

Cuatro, WebSocket

principio:

Cuando un cliente se conecta al servidor, se enviará un siguiente similares http paquete al servidor:

se puede ver, se trata de un mensaje de solicitud HTTP GET, anote el mensaje no es una cabecera de actualización, su función es decirle al servicio de protocolo de comunicación final necesita ser cambiado a WebSocket, si el acuerdo WebSocket soporte el servidor, entonces será el propietario de conmutación protocolo de comunicación a WebSocket, al mismo tiempo para el cliente una respuesta similar a la siguiente cabecera:

el código de estado de retorno 101 , estaba de acuerdo con la solicitud de conversión de protocolos de cliente, y lo convierte a un acuerdo WebSocket. El proceso anterior se lleva a cabo utilizando la comunicación HTTP, llamado WebSocket protocolo de enlace (WebSocket protocolo de enlace), después de estado en este apretón de manos, el cliente y el servidor para establecer una conexión WebSocket, después de la comunicación están tomando la WebSocket el acuerdo. Entonces, para resumir WebSocket necesitan la ayuda de http protocolo de enlace, la conexión se establece mediante el acuerdo WebSocket proceso de comunicación. Al mismo tiempo la necesidad de entender que la conexión se basa en WebSocket que acabamos de lanzar la conexión TCP HTTP. Una vez después de que se haya establecido la conexión, podemos transferir los datos, WebSocket proporciona una transmisión de dos datos: datos de texto y datos binarios.

-javax.websocket del lado del servidor

cliente

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>
<!DOCTYPE HTML>
<html>
<head>
<title>Java后端WebSocket的Tomcat实现</title>
<script type="text/javascript">
	var websocket = null;
	var host = document.location.host;
	function connect() {
		//判断当前浏览器是否支持WebSocket
		if ('WebSocket' in window) {
			var value = document.getElementById("b").value;
			websocket = new WebSocket("ws://" + host + "/exam5/websocket/" + value);
			//连接发生错误的回调方法
			websocket.onerror = function() {
				setMessageInnerHTML("WebSocket连接发生错误");
			};
			//连接成功建立的回调方法
			websocket.onopen = function() {
				setMessageInnerHTML("WebSocket连接成功");
			}
			//接收到消息的回调方法
			websocket.onmessage = function(event) {
				setMessageInnerHTML(event.data);
			}
			//连接关闭的回调方法
			websocket.onclose = function() {
				setMessageInnerHTML("WebSocket连接关闭");
			}
			//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
			window.onbeforeunload = function() {
				closeWebSocket();
			}
		} else {
			alert('当前浏览器 Not support websocket')
		}
	}
	//将消息显示在网页上
	function setMessageInnerHTML(innerHTML) {
		document.getElementById('message').innerHTML += innerHTML + '<br/>';
	}
	//关闭WebSocket连接
	function closeWebSocket() {
		websocket.close();
	}
	//发送消息
	function send() {
		var message = document.getElementById('text').value;
		websocket.send(message);
	}
</script>
</head>
<body>
	Welcome
	<br />
	<input id="text" type="text" />
	<input type="button" onclick="send()" value="发送消息"/>
	<br />
	<input id="b" type="text" />
	<!-- 这里用于注册不同的clientId, 多个webSocket客户端只能同步收到相同clientId的消息 -->
	<input type="button" onclick="connect()" value="连接"/>
	<hr />
	<input type="button" onclick="closeWebSocket()" value="关闭WebSocket连接"/>
	<hr />
	<div id="message"></div>
</body>
</html>
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
 
/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
 *                 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint("/websocket/{clientId}")
public class WebSocket {
	// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
	private static AtomicInteger onlineCount = new AtomicInteger(0);
	// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
	//若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
	// private static CopyOnWriteArraySet<WebSocket> webSocketSet = new
	// CopyOnWriteArraySet<WebSocket>();
	// 与某个客户端的连接会话,需要通过它来给客户端发送数据
	//记录每个客户端的实例变量, 现在拿下面的全局map记录 
	//private Session session;
	private static Map<String, Session> webSocketMap = new ConcurrentHashMap<String, Session>();

	/**
	 * 连接建立成功调用的方法
	 * 
	 * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
	 */
	@OnOpen
	public void onOpen(@PathParam("clientId") String clientId, Session session) {
		// 用登录用户编号和sessionId的拼接来做webSocket通信的唯一标识
		String key = getWebSocketMapKey(clientId, session);
		webSocketMap.put(key, session);
		addOnlineCount(); // 在线数加1
		System.out.println("WebSocket有新连接加入!当前在线人数为" + getOnlineCount());
	}
	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose(@PathParam("clientId") String clientId, Session session, CloseReason closeReason) {
		String key = getWebSocketMapKey(clientId, session);
		webSocketMap.remove(key, session);
		subOnlineCount(); // 在线数减1
		System.out.println("WebSocket有一连接关闭!当前在线人数为" + getOnlineCount());
	}
 
	/**
	 * 收到客户端消息后调用的方法
	 * 
	 * @param message 客户端发送过来的消息
	 * @param session 可选的参数
	 */
	@OnMessage
	public void onMessage(@PathParam("clientId") String clientId, String message, Session session) {
		System.out.println("WebSocket收到来自客户端的消息:" + message);
		sendMessageByClientId(clientId, message);
	}
 
	/**
	 * 获取webSocketMap集合的Key
	 * 
	 * @param clientId 用户编号
	 * @param session  webSocket的Session
	 * @return
	 */
	private String getWebSocketMapKey(String clientId, Session session) {
		if (clientId==null) {
			return session.getId();
 
		} else {
			return clientId + "_" + session.getId();
		}
	}
	/**
	 * 发生错误时调用
	 * 
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
 
		System.out.println("WebSocket发生错误");
	}
 
 
	// 群发消息
	public static void doSend(String message) {
		if (webSocketMap.size() > 0) {
			for (Map.Entry<String, Session> entry : webSocketMap.entrySet()) {
				try {
					sendMessage(entry.getValue(), message);
				} catch (IOException e) {
					System.out.println("WebSocket doSend is error:");
					continue;
				}
			}
		}
	}
 
	public static void sendMessage(Session session, String message) throws IOException {
		session.getBasicRemote().sendText(message);
	}
 
	public static int sendMessageByClientIdList(List<String> clientIdList, String message) {
		int status = 0;
		for (String clientId : clientIdList) {
			status = sendMessageByClientId(clientId, message);
		}
		return status;
	}
 
	/**
	 * 通过用户的编号来发送webSocket消息
	 * 
	 * @param clientId
	 * @param message
	 */
	public static int sendMessageByClientId(String clientId, String message) {
		int status = 0;
		if (webSocketMap.size() > 0) {
			for (Map.Entry<String, Session> entry : webSocketMap.entrySet()) {
				try {
					String key = entry.getKey();
					// 判断webSocketMap中的clientId和发送的clientId是否相同
					// 若相同则进行发送消息
					String key1 = key.substring(0, key.lastIndexOf("_"));
					if (key1.equals(clientId)) {
						sendMessage(entry.getValue(), message);
						status = 200;
					}
				} catch (IOException e) {
					System.out.println("WebSocket doSend is error:");
					continue;
				}
			}
		}
		return status;
	}
 
	public static void sendSpeechMessageByClientId(String clientId, String message) {
		if (webSocketMap.size() > 0) {
			for (Map.Entry<String, Session> entry : webSocketMap.entrySet()) {
				try {
					String key = entry.getKey();
					// 判断webSocketMap中的clientId和发送的clientId是否相同
					// 若相同则进行发送消息
					String key1 = key.substring(0, key.lastIndexOf("_"));
					if (key1.equals(clientId)) {
						sendMessage(entry.getValue(), message);
					}
				} catch (IOException e) {
					System.out.println("WebSocket doSend is error:");
					continue;
				}
			}
		}
	}
 
	public static synchronized AtomicInteger getOnlineCount() {
		return onlineCount;
	}
 
	public static synchronized void addOnlineCount() {
		WebSocket.onlineCount.getAndIncrement();
	}
 
	public static synchronized void subOnlineCount() {
		WebSocket.onlineCount.getAndDecrement();
	}
}

 

 

 

Publicados 349 artículos originales · ganado elogios 161 · vistas 190 000 +

Supongo que te gusta

Origin blog.csdn.net/qq_42192693/article/details/103864780
Recomendado
Clasificación