本博文,保证不用装B的话语和太多专业的语言,保证简单易懂,只要懂JAVAEE开发的人都可以看懂。 本博文发表目的是,目前网上针对Websocket的资料太散乱,导致初学者的知识体系零零散散,学习困难加大。本博加以整理,并且实践。

所用核心技术选型:

Tomcat + Spring 4.0.3 + Mongodb(高并发数据库)

+ SpringQueue(消息队列)+ ActiveMQ (消息队列)

+ Spring-data-Mongo + Servlet 3.0

+Spring-Websocket

+ Maven

注:以下Websocket 均省略成 WB

先说Websocket 的原理。 Websocket 是全双工通讯(说白了就是俩都可以通讯,服务器也可以给客户端发消息,客户端也能给服务器发消息)。也是基于TCP的,效率是很高的,首先这个技术的底层选用,就决定了完全可以用wb这个技术做高并发应用,而且开发非常快!!代码非常简单!!最重要的是稳定性,扩展性等等都有保证,等会儿说为什么说都有保证。

WB 不同于TCP的三次握手。  WB是先进行一次HTTP请求,这个请求头不同于普通HTTP请求,等会贴出来讲解。然后服务器开始辨认请求头,如果是WB的请求头,则开始进行普通的TCP连接,即三次握手(不懂的TCP的,出门百度)。如果不是WB的HTTP请求头,那就是按普通的HTTP请求处理。

流程梳理: HTTP特殊请求(有个特殊的头) ---- 》 服务请接收判断 ----- 》 认出来了,确实是WB请求头,开启TCP 三次握手,建立连接后,和TCP一样了就------》没有认出来,不是WB的请求头,按普通HTTP请求处理。

很清楚了吧。这是个基础,先理解了,下面写程序才好搞。下面这段是Webscoket的请求头。 GET请求

GET ws://localhost:12345/websocket/test.html HTTP/1.1
Origin: http://localhost
Connection: Upgrade
Host: localhost:12345
Sec-WebSocket-Key: JspZdPxs9MrWCt3j6h7KdQ== //主要这个字段,这个叫“梦幻字符串”,这个加密规则可以去百度,是有规则的。这个也是个密钥,只有有这个密钥 服务器才能通过解码 认出来,哦~这是个WB的请求,我要建立TCP连接了!!!如果这个字符串没有按照加密规则加密,那服务端就认不出来,就会认为这整个协议就是个HTTP请求。更不会开TCP。其他的字段都可以随便设置,但是这个字段是最重要的字段,标识WB协议的一个字段。
Upgrade: websocket
Sec-WebSocket-Version: 13

下面这段是服务端回应消息:

HTTP/1.1 101 Web Socket Protocol Handshake
WebSocket-Location: ws://localhost:12345/websocket/test.php
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: zUyzbJdkVJjhhu8KiAUCDmHtY/o= //这个字段,叫“梦幻字符串”,和上面那个梦幻字符串作用一样。不同的是,这个字符串是要让客户端辨认的,客户端拿到后自动解码。并且辨认是不是一个WB请求。然后进行相应的操作。这个字段也是重中之重,不可随便修改的。加密规则,依然是有规则的,可以去百度一下。
WebSocket-Origin: http://localhost

好了,一去一回的HTTP请求, 如果他们的梦幻字符串都对上了,客户端服务端都确定是一次WB请求了。。那就开始建立TCP连接了。

关于Tcp编程,为什么没有选用Netty或者Mina框架,而选用以上的技术。 其实我感觉还是他们太复杂。并且,我们用Netty的话,集群规则,负载均衡,JVM优化都需要自己做。集群规则,负载均衡这块儿,就是另一个大的研究方向,一个人根本搞不下来。

不如放在容器里。比如Tomcat,你要真嫌弃Tomcat太低端。换Jboss也不是不行,他们都做了N年的优化和开发,稳定性绝对OK,集群规则,负载均衡,JVM等等都有现成的解决方案,还有其他的一些优化 ,可以说世界顶尖。满足你的高并发一点问题都没。

不要重复造轮子!!别人(JBoss)的集群规则好,负载均衡稳定,就用就是了!!!!所以,小的WB应用推荐tomcat,高并发的WB应用,推荐Jboss。并且合理设置集群规则,合理配置负载均衡,合理优化JVM,我保证,满足你的高并发websocket需求完全不是问题。。

加上我们的数据库选型和消息队列,都是为高并发添火的技术,所以代码写的干净的话,高并发完全不是问题。不用纠结,WB的效率如何,集群怎么做~负载均衡是不是要自己写。。答案是NO。 解决方案是 用高端点的应用容器!!

这就是WB和TCP比的优势!!他可以在容器里搞~ 集群方案,负载均衡方案都是人家做好的。

原生的TCP协议,你必须自己去解决这些问题。这真是一个大问题,想想就知道了,单单集群这块儿,有几个能做的好的。。

先贴pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mendao</groupId>
<artifactId>websocket</artifactId>
<packaging>war</packaging>
<version>1.0.0</version>
<description>门道的即时通讯服务器</description> <properties>
<!--Fast Json-->
<fastjson.version>1.1.39</fastjson.version> <!-- Servlet 版本号 -->
<servlet.version>3.1.0</servlet.version> <!-- spring版本号 3.2.8.RELEASE -->
<spring.version>4.0.3.RELEASE</spring.version> <!-- Hibernate版本号 4.3.5.Final -->
<hibernate.version>3.6.10.Final</hibernate.version> <!-- mysql版本号 -->
<mysql.version>5.1.30</mysql.version> <!--logback-->
<logback.version>1.1.2</logback.version> <!-- xmemcached 版本号 -->
<xmemcached.version>2.0.0</xmemcached.version> <!--Activemq -->
<activemq.version>5.7.0</activemq.version> <!-- 高速序列化框架 -->
<kryo.version>2.23.0</kryo.version> <!--tomcat-->
<tomcat.version>8.0.5</tomcat.version>
</properties> <dependencies>
<!-- 高性能 序列化框架 -->
<dependency>
<groupId>com.esotericsoftware.kryo</groupId>
<artifactId>kryo</artifactId>
<version>${kryo.version}</version>
</dependency>
<!--异步消息队列-->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>3.17</version>
</dependency> <!-- 必须包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency> <!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.4.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.2.1.RELEASE</version>
</dependency> <!-- mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency> <!-- FastJson 来处理JSON数据 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency> <!-- logback-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency> <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency> <!-- xmemcached 缓存服务器 -->
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>${xmemcached.version}</version>
</dependency> <!--Common 系列-->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<!--加密解密,编码解码-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency> <!--Tomcat 环境支持-->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-websocket</artifactId>
<version>${tomcat.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-coyote</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency> </dependencies> <build>
<finalName>ROOT</finalName>
<plugins>
<!-- 使用JDK1.7编译java源文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin> <!-- 使用UTF-8编码资源文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin> <!--WAR 打包插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build> </project>

然后,开始进入正题。web.xml配置。我贴上我的配置。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javeee/web-app_3_0.xsd"
version="3.0"> <!--关键点!servlet要是3.0不能再是2.5了--> <welcome-file-list>
<welcome-file>welcome.html</welcome-file>
</welcome-file-list> <servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
com.mendao.config.WebConfig <!--关键点!我们需要用spring的全注解配置方式来配置websocket,所以这块儿需要指向你的对应的类-->
</param-value>
</init-param>
</servlet> <!-- Spring MVC -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern> <!--关键点!一旦你使用wb 就不能使用普通的springmvc里的HTTP请求了,也就是要么这个程序使用WB的技术要么使用springmvc的技术,二者不可兼得!!所以WB和Springmvc必须分开程序写-->
</servlet-mapping> <!-- Spring 监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--Spring Request 监听器-->
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener> <!-- 编码强转 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <!-- Spring 刷新Introspector防止内存泄露 请求多了会内存泄露,加上他就好了-->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
</web-app>

web.xml没什么可说的了。主要点已经标注。然后贴上

com.mendao.config.WebConfig 

这个类让大家一看究竟!!完全可以直接复制下来

/**
* WebSocket 配置类
*/
@Configuration //一定不能少
@ImportResource("classpath*:/applicationContext.xml") //重要!!加载spring的其他的xml配置文件,这种方式是注解方式+xml方式 相结合的配置方式!!
@EnableWebSocket //不能少
public class WebConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { @Resource
private BootstrapHandler clientHandler; //注入实例
@Resource
private Bootstrapnterceptor interceptor; //注入实例 @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {//重要!处理器 URL地址 拦截器!! 都在这里加入!!//等会儿帖 处理器和 拦截器的代码 //你需要更多处理器 或者URL 都在这里填就是了。其实一般一个就够了,一个核心处理器做请求中转。
registry.addHandler(clientHandler, "/bootstrap").addInterceptors(interceptor);
} // Allow serving HTML files through the default Servlet // 完全可以无视下面的代码 @Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
} }

下面是BootstrapHandler 的代码!都有注释

@Service
public class BootstrapHandler implements WebSocketHandler { private final Logger logger = LoggerFactory.getLogger(BootstrapHandler.class);
@Resource
private BootstrapHandlerService bootstrapHandlerService;
@Resource
private Cached cached; /**
* 双工通讯 连接后 并且在这里心跳
*
* @param session
* @throws Exception
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
TextMessage textMessage;
try {
HttpHeaders headers = session.getHandshakeHeaders();
String userAgent = headers.get("user-agent").get(0);
logger.info("LOGIN : " + userAgent);
       //构造回应的消息,每次连接成功后要回应消息吖!告诉客户端已经连接成功了!消息就在这里面构造
textMessage = new TextMessage(“连接成功”);
} catch (Exception e) {
e.printStackTrace();
textMessage = new TextMessage(“连接失败”);
}
     //这样就发送给客户端了~ 很简单!!
session.sendMessage(textMessage);
} /**
* 处理发送过来的消息
*
* @param session
* @param message
* @throws Exception
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage message) throws Exception {
try {
       //如果连接成功!!这里面会不停的接收到心跳包!! 怎么处理~看你的了!!! 总之这个方法就是接受客户端发来消息的方法!!!        // message.getPayload()得到的是客户端发来的消息,比如“你好啊!” 之类的。得到后转成String就能处理了!
StringBuffer sb = new StringBuffer((String) message.getPayload());
       //这个是我自己写的一个处理业务逻辑。你可以实现自己的业务逻辑
bootstrapHandlerService.handleMessage(session, sb);
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage());
}
} /**
* 客户端 异常断开
*
* @param session
* @param throwable
* @throws Exception
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable throwable) throws Exception {
logger.info(session.getId() + " - 异常断开连接");
//所谓异常断开,例如:突然关闭HTML页面等等,总之不是用户正常关闭的!
     //这个也是我自己实现的 异常处理的业务逻辑,你可以自己写
bootstrapHandlerService.handleError(session, throwable);
} /**
* 连接已经断 开
*
* @param session
* @param status
* @throws Exception
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
     //只要是断开连接!不管是异常断开,还是普通正常断开,一定会进入这个方法。
String reason = status.getReason();
if (reason == null) {
reason = "客户端 按指令正常退出";
}
    
logger.info(session.getId() + " - 已经主动关闭连接 - 关闭码 - " + status.getCode() + " - 缘由 -" + reason);
//其实这里面封装了个session.close()释放了一些资源, 也是我自己实现的业务逻辑,你也可以自己写!
bootstrapHandlerService.connectionClose(session);
} /**
* 握手成功 初始化操作在这里面进行
*
* @return
*/
@Override
public boolean supportsPartialMessages() {
      //一旦HTTP认证成功 这个方法先被调用 如果返回true 则进行上面那么N多方法的流程。如果返回的是false就直接拦截掉了。不会调用上面那些方法了!!
//就好像个构造器一样。这个是处理器 BootstrapHandler的构造器~
return true;
} }

然后贴上 Interceptor 拦截器的代码!! 实现的接口不能变!!里面没代码的原因是 我实在不知道在这里面做什么操作,感觉我的业务是用不到这两个方法。

@Service
public class Bootstrapnterceptor implements HandshakeInterceptor { /**
* 握手前
*
* @param request
* @param response
* @param webSocketHandler
* @param stringObjectMap
* @return
* @throws Exception
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler webSocketHandler, Map<String, Object> stringObjectMap) throws Exception {
return true;
} /**
* 握手成功后
*
* @param request
* @param response
* @param handler
* @param e
*/
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Exception e) {
}
}

然后我上一个HTML版的客户端测试程序!!

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>w</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
var heartbeat_timer = 0;
var last_health = -1;
var health_timeout = 3000; $(function(){
//ws = ws_conn( "ws://211.100.41.186:9999" );
ws = ws_conn( "ws://127.0.0.1:12345/bootstrap"); $("#send_btn").click(function(){
var msg = $("#mysendbox").val();
alert(msg);
alert(ws);
ws.send(msg);
$("#mysendbox").val("");
});
}); function keepalive( ws ){
var time = new Date();
if( last_health != -1 && ( time.getTime() - last_health > health_timeout ) ){
//此时即可以认为连接断开,可是设置重连或者关闭
$("#keeplive_box").html( "服务器没有响应." ).css({"color":"red"});
//ws.close();
}
else{
$("#keeplive_box").html( "连接正常" ).css({"color":"green"});
if( ws.bufferedAmount == 0 ){
ws.send( '1'); }
}
} //websocket function
function ws_conn( to_url ){
to_url = to_url || "";
if( to_url == "" ){
return false;
} clearInterval( heartbeat_timer );
$("#statustxt").html("Connecting...");
var ws = new WebSocket( to_url );
ws.onopen=function(){
$("#statustxt").html("connected.");
$("#send_btn").attr("disabled", false);
heartbeat_timer = setInterval( function(){keepalive(ws)}, 5000 );
}
ws.onerror=function(){
$("#statustxt").html("error.");
$("#send_btn").attr("disabled", true);
clearInterval( heartbeat_timer );
$("#keeplive_box").html( "连接出错." ).css({"color":"red"});
}
ws.onclose=function(){
$("#statustxt").html("closed.");
$("#send_btn").attr("disabled", true);
clearInterval( heartbeat_timer );
$("#keeplive_box").html( "连接已关闭." ).css({"color":"red"});
} ws.onmessage=function(msg){
var time = new Date();
if( msg.data == ( '1' ) ){
last_health = time.getTime();
return;
} $("#chatbox").val( $("#chatbox").val() + msg.data + "\n" );
$("#chatbox").attr("scrollTop",$("#chatbox").attr("scrollHeight"));
} return ws;
}
</script>
</head> <body> <p>web socket连接状态:&nbsp;&nbsp;<span id="statustxt">连接中...</span></p>
<p>心跳状态:<span id="keeplive_box">检测中...</span></p>
<p>
<textarea name="chatbox" id="chatbox" cols="55" rows="20" readonly="readonly"></textarea>
</p>
<p>
<p>发送文本到Websocket服务器</p>
<input name="mysendbox" type="text" id="mysendbox" size="50" />
&nbsp;
<input type="button" name="send_btn" id="send_btn" value="Send" disabled="disabled" />
<input type="button" onclick="javascript:ws.close()" value="Close"/>
</p>
</body>
</html>

核心的就这么多。

这些方法理解了,其他的,靠自己发挥想象~

对了,每个不同的连接都会有一个不同的WebSocketSession session   你可以把这个session存入一个全局的ConcurrentHashMap中!!作为连接池!!

用的时候 用 map.get(key); 然后就能用sendMessage(); 发送给他消息了!!!

什么时候存这个session,这就看你的业务需要了。总之每个WebSocketSession 标识一个完全不同的新的连接。客户句柄来形容,也可以~

然后虽然你用上了WB 但是还是要自己做出来。心跳包~ 数据分割处理~ 等等一些基本的业务逻辑~ 什么地方用消息队列分发,那就要看你业务怎么设计了。

最后!!最有用的!!websocket可以做移动端 (安卓IOS等)即时通讯服务器。但是需要用到一个jar包。在github上搜索 websocket client (websocket的客户端) 有java的实现也有object-c的实现

这个思路提供出来之后,你就知道websocket 的强大了吧。不但敏捷开发!而且跨平台!!可以做android推送解决方案!! 当然也可以整合ios做即时通讯!!当然!!HTML更可以!因为原生的就是HTML!!! 强大的websocket为企业即时通讯方案提供了更好的出路!!!

核心已经讲解!更多的发挥想象吧!!!

Websocket全讲解。跨平台的通讯协议 !!基于websocket的高并发即时通讯服务器开发。的更多相关文章

  1. 基于RTKLIB构建高并发通信测试工具

    1. RTKLIB基础动态库生成 RTKLIB是全球导航卫星系统GNSS(global navigation satellite system)的标准&精密定位开源程序包,由日本东京海洋大学的 ...

  2. 基于SOA的高并发和高可用分布式系统架构和组件详解

    基于SOA的分布式高可用架构和微服务架构,是时下如日中天的互联网企业级系统开发架构选择方案.在核心思想上,两者都主张对系统的横向细分和扩展,按不同的业务功能模块来对系统进行分割并且使用一定的手段实现服 ...

  3. 个人项目开源之c++基于epoll实现高并发游戏盒子(服务端+客户端)源代码

    正在陆续开源自己的一些项目 此为c++实现高并发的游戏盒子,平台问题需要迁移重构,所以有一些遗留问题,客户端异常断开没有处理,会导致服务器崩溃,还有基于快写代码编程平台实现的小程序切换,线程读写缓存没 ...

  4. AssassinGo: 基于Go的高并发可拓展式Web渗透框架

    转载自FreeBuf.COM AssassinGo是一款使用Golang开发,集成了信息收集.基础攻击探测.Google-Hacking域名搜索和PoC批量检测等功能的Web渗透框架,并且有着基于Vu ...

  5. Linux下基于Erlang的高并发TCP连接压力实验

    1.实验环境: 联想小型机: 操作系统:RedHat Enterprise LinuxServer release6.4(Santiago) 内核版本号:Linux server1 2.6.32-35 ...

  6. 基于redis的高并发秒杀的JAVA-DEMO实现!

    在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能.假设我们通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EX ...

  7. 基于 websocket 实现的 im 实时通讯案例

    分享利用 redis 订阅与发布特性,巧妙的现实高性能im系统.为表诚意,先贴源码地址:https://github.com/2881099/im 下载源码后的运行方法: 运行环境:.NETCore ...

  8. 基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)

    今天我们来盘一盘Socket通讯和WebSocket协议在即时通讯的小应用——聊天. 理论大家估计都知道得差不多了,小编也通过查阅各种资料对理论知识进行了充电,发现好多demo似懂非懂,拷贝回来又运行 ...

  9. springboot+websocket+sockjs进行消息推送【基于STOMP协议】

    springboot+websocket+sockjs进行消息推送[基于STOMP协议] WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就 ...

随机推荐

  1. Android 遮罩层效果

    (用别人的代码进行分析) 不知道在开发中有没有经常使用到这种效果,所谓的遮罩层就是给一张图片不是我们想要的形状,这个时候我们就可以使用遮罩效果把这个图片变成我们想要的形状,一般使用最多就是圆形的效果, ...

  2. ng animate

    要在angular中加入动画必须引入angular.animate.js插件,然后就可以在module中引入ngAnimate模块.如: var module1 = angular.module('m ...

  3. Asp.Net MVC4入门指南(10):第三方控件Studio for ASP.NET Wijmo MVC4 工具应用

    ComponentOne Studio for ASP.NET Wijmo最新版本2013V1支持MVC4,其中包括: 新增 MVC 4 工程模板 (C# & VB) 开箱即用的MVC 4 工 ...

  4. C/C++中extern关键字解析

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

  5. [Docker]Docker快速上手学习笔记

    0. 学习的一些疑问 如何热更新镜像(images)?(你可以快速启动或者销毁容器.这种时间几乎是实时的) 如何热更新游戏服? 好处在于各个应用之间环境相互独立,即使某一个容器崩溃也不会影响到其它容器 ...

  6. MySQL Create Table创建表

    表的创建命令需要: 表的名称 字段名称 定义每个字段(类型.长度等) 语法 下面是通用的SQL语法用来创建MySQL表: CREATE TABLE table_name (column_name co ...

  7. .NET J2EE APP全局会话架构运用场景

    .NET J2EE APP全局会话架构运用场景, 全局会话运用拓扑图代码核心架构为.NET架构开发C#语言为主代码架构分为全局会话中心.ASP.NET会话节点..NET会话节点针对WCF服务器与APP ...

  8. 产生NaN

    1.数学运算失败  数字+undefind=NaN 2.数据类型转化失败产生NaN isNaN()检查 是不是一个有效数字,是NaN 返回 ture  ,正常数字返回false.

  9. WinForm 文本框验证

    这是一个自定义控件,继承了TextBox,在TextBox基础上添加了4个属性(下载): 1.ControlType 文本框需要验证的类型 2.ControlTypeText 显示的文字(只读) 3. ...

  10. Popup - 弹出层

    //图片类快捷弹出层 <a href="" target="_blank"> <div class="panlifang1" ...