wetrtc-android客户端连接过程图
TCP协议中的三次握手和四次挥手(图解)

TCP协议中的三次握手和四次挥手(图解)TCP协议中的三次握手和四次挥手(图解) 建立TCP需要三次握手才能建立,而断开连接则需要四次握手。
整个过程如下图所示:先来看看如何建立连接的。
首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源。
Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了。
那如何断开连接呢?简单的过程如下:【注意】中断连接端可以是Client端,也可以是Server端。
假设Client端发起中断连接请求,也就是发送FIN报文。
Server端接到FIN报文后,意思是说”我Client端没有数据要发给你了”,但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。
所以你先发送ACK,”告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息”。
这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。
当Server端确定数据已发送完成,则向Client端发送FIN报文,”告诉Client端,好了,我这边数据发完了,准备好关闭连接了”。
Client端收到FIN报文后,”就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_W AIT状态,如果Server端没有收到ACK则可以重传。
“,Server端收到ACK后,”就知道可以断开连接了”。
Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client 端也可以关闭连接了。
Ok,TCP连接就这样关闭了!整个过程Client端所经历的状态如下:而Server端所经历的过程如下:【注意】在TIME_W AIT状态中,如果TCP client端最后一次发送的ACK丢失了,它将重新发送。
TIME_W AIT状态中所需要的时间是依赖于实现方法的。
腾讯通(RTX)安卓版手机客户端安装使用方法

腾讯通(RTX)安卓版手机客户端安装使用方法
在android手机上安装“AndroidDemo(beta).apk”,安装文件可先通过数据线或QQ硬盘等工具传到手机上,安装前,须在android手机“设置”的“应用程序”中允许“未知源”,安装完成后,在“全部应用程序”中出现“企业通讯录”,即是手机客户端,如下图:
如果已经安装过旧版本,可直接在手机RTX客户端的“更多-关于-检查新版本”升级,如图:
运行“企业通讯录”,填写服务端配置的总机号及RTX员工帐号密码,注意空密码不能登录:
登录成功之后即可使用手机客户端了,基本功能页包括“会话”、“联系人”、“组织架构”及“设置”:
会话列表包括“单人会话”、“多人会话”、“群消息”、“系统广播”、“系统提醒”各种RTX消息类型,支持离线消息和即时对话,最新的消息列表排在列表的最上面,进入具体会话后,最新一句对话会在最下面,如图:
点击右上角的可主动发起会话。
如果客户端平时没有打开,有新消息来了之后会在安卓系统桌面顶端的消息
栏提示,如图:
联系人页面,指的是常用联系人及常用联系组,通过长按会话列表中的联系人及多人会话添加,如下图:。
互联网推送服务原理:长连接+心跳机制(MQTT协议)IT瘾

互联网推送服务原理:长连接+心跳机制(MQTT协议)IT瘾互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了,所以才会出现像MQTT这种轻量级低消耗的协议来维护长连接,那么要如何维护长连接呢:在写之前,我们首先了解一下为什么android维护长连接需要心跳机制,首先我们知道,维护任何一个长连接都需要心跳机制,客户端发送一个心跳给服务器,服务器给客户端一个心跳应答,这样就形成客户端服务器的一次完整的握手,这个握手是让双方都知道他们之间的连接是没有断开,客户端是在线的。
如果超过一个时间的阈值,客户端没有收到服务器的应答,或者服务器没有收到客户端的心跳,那么对客户端来说则断开与服务器的连接重新建立一个连接,对服务器来说只要断开这个连接即可。
那么在智能手机上的长连接心跳和在Internet上的长连接心跳有什么不同的目的呢?原因就在于智能手机使用的是移动无线网络,那么我们在讲长连接之前我们首先要了解无线移动网络的特点。
1.无线移动网络的特点:当一台智能手机连上移动网络时,其实并没有真正连接上Internet,运营商分配给手机的IP其实是运营商的内网IP,手机终端要连接上Internet还必须通过运营商的网关进行IP地址的转换,这个网关简称为NAT(NetWork Address Translation),简单来说就是手机终端连接Internet 其实就是移动内网IP,端口,外网IP之间相互映射。
相当于在手机终端在移动无线网络这堵墙上打个洞与外面的Internet相连。
原理图如下:(来源网络)GGSN(GateWay GPRS Support Note 网关GPRS支持节点)模块就实现了NAT功能,由于大部分的移动无线网络运营商为了减少网关NAT映射表的负荷,如果一个链路有一段时间没有通信时就会删除其对应表,造成链路中断,正是这种刻意缩短空闲连接的释放超时,原本是想节省信道资源的作用,没想到让互联网的应用不得以远高于正常频率发送心跳来维护推送的长连接。
Android客户端与PC服务器实现Socket通信(wifi)

Android客户端与PC服务器实现Socket通信(wifi)本文介绍Android终端持续扫描AP信息并发送给服务器端的实现。
首先基于TCP协议在Android终端和PC两端之间形成网络虚拟链路。
使用ServerSocket创建TCP服务器端,然后在Android客户端使用Socket的构造器来连接服务器。
其中Android终端通过WIFI连接和PC处于同一局域网。
1. PC服务器启用ServerSocket两个通信实体在建立虚拟链路之前,需要有一方先准备好,主动接受来自其他通信实体的连接请求。
使用ServerSocket对象监听来自客户端的Socket连接//创建ServerSocket对象ServerSocket ss = new ServerSocket(30000);//监听来自客户端的请求while(true){Socket s = ss.accept();…}如果没有连接,则将一直处于等待状态。
当接收到连接请求后,获取消息到输入流,并保存到文件。
//接收客户端消息BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); String str;BufferedWriter bw = new BufferedWriter(new FileWriter("D:/ApInfo"+ (i++) +".txt"));while ((str = in.readLine()) != null) {System.out.println(str);bw.write(str);bw.newLine();}2. Android终端使用Socket通信客户端使用Socket的构造器连接服务器,指定服务器IP和端口号就可以了。
Socket s = new Socket(“192.168.1.100”, 30000);这样服务器端的accept()方法就得到响应,从而向下执行,服务器端和客户端就形成了一对互相连接的Socket。
Wecenter3.1.3问题接口使用手册-ET采集

Wecenter3.1.3问题接口使用手册一、简介1、本接口应用于问答社区wencenter 3.1.3版发布新问题和回复;2、本接口可自动创建话题,显示图片,不支持附件入库。
3、发布时使用的用户帐号应有相应权限;4、接口文件无须任何改动即可使用,如果你希望增加校验或其他功能,请仔细修改;5、接口文件请复制在指定目录下使用;二、安装接口在接口文件夹中找到接口文件,如图:请将etpost.php、etreply.php 文件上传到指定目录,请使用二进制方式上传,如图:三、配置发布规则1、将范例发布规则文本导入ET2发布配置,或使用软件内置发布规则范例,如图:2、将检查网址和发布网址中的“您的网站”改为您要发布的网站网址,如图:3、在参数取值页,填上您要发布的分类ID,如图:在分类链接中可查看该分类ID号,例如:http://localhost/?/home/explore/category-1 中末尾的1即分类ID号。
4、填上发起问题的用户账号、密码,注意格式和账号权限,如图:四、接口说明一、检查接口无独立检查接口文件,检查问题重复功能集合在发布接口中,见参数ischk 和ischkcategory的说明。
二、发布接口1、接口文件名etpost.php,不可修改文件名;2、本接口文件请复制在网站\app\et目录下使用(et子目录请创建);接口参数:请在发布规则-发布项中设置参数,参数取值可以指定,也可以与采集规则的数据项对应,如图:3、基本参数user_name用户名参数名password密码参数名question_content问题标题参数名;question_detail问题正文参数名;4、重要参数category_id分类ID参数名,可通过分类链接查看ID;topics[]话题参数名,多个话题请在参数取值添加多条,如图:如果是没有的新话题,使用具有创建话题权限的帐号发布则会自动创建。
5、可选参数anonymous是否匿名发布,1为是,0或留空为否;ischk是否检查问题标题重复,1为是,0或留空为否;ischkcategory检查问题标题重复时是否按分类检查,1为是,0或留空为否;6、内容格式wecenter3使用UBB代码,应在发布配置中选择使用UBB和保留换行符。
LTE信令流程图(端到端平台)

TDD-LTE 基本信令流程图1 概述本文主要针对TD-LTE端到端信令流程图进行分解,为端到端平台提供分析流程呈现依据。
由于部分流程无S1口信令支撑,当前根据相关文档进行的绘制,后续具备条件后进行补充调整。
2 TDD-LTE网络结构概述LTE的系统架构分成两部分,包括演进后的核心网EPC(MME/S-GW)和演进后的接入网E-UTRAN。
演进后的系统仅存在分组交换域。
LTE接入网仅由演进后的节点B(evolved NodeB)组成,提供到UE的E-UTRA控制面与用户面的协议终止点。
eNB之间通过X2接口进行连接,并且在需要通信的两个不同eNB之间总是会存在X2接口。
LTE接入网与核心网之间通过S1接口进行连接,S1接口支持多—多联系方式。
与3G网络架构相比,接入网仅包括eNB一种逻辑节点,网络架构中节点数量减少,网络架构更加趋于扁平化。
扁平化网络架构降低了呼叫建立时延以及用户数据的传输时延,也会降低OPEX与CAPEX。
由于eNB与MME/S-GW之间具有灵活的连接(S1-flex),UE在移动过程中仍然可以驻留在相同的MME/S-GW上,有助于减少接口信令交互数量以及MME/S-GW的处理负荷。
当MME/S-GW与eNB之间的连接路径相当长或进行新的资源分配时,与UE连接的MME/S-GW 也可能会改变。
E-UTRAN2.1 EPC 与E-UTRAN 功能划分与3G 系统相比,由于重新定义了系统网络架构,核心网和接入网之间的功能划分也随之有所变化,需要重新明确以适应新的架构和LTE 的系统需求。
针对LTE 的系统架构,网络功能划分如下图:eNodeB 功能:1) 无线资源管理相关的功能,包括无线承载控制、接纳控制、连接移动性管理、上/下行动态资源分配/调度等; 2) IP 头压缩与用户数据流加密; 3) UE 附着时的MME 选择;4) 提供到S-GW 的用户面数据的路由; 5) 寻呼消息的调度与传输; 6) 系统广播信息的调度与传输; 7) 测量与测量报告的配置。
Android平台网络连接架构分析-connectivityservice框架流程word版本

Android平台网络连接架构解析2016-09李国辉ligh6@一概述截止到最新的7.0版本,android网络连接管理系统一直都由四个service组成,分别是ConnectivityService,NetworkPolicyManagerService,NetworkManagementService,NetworkStatsService共同配合完成网络连接和管理功能,其中核心服务是ConnectivityService,而本文也会着重介绍该service的架构,四个service中NetworkPolicyManagerService通过NetworkPolicyManager对外提供SDK接口,而ConnectivityService通过ConnectivityManager对外提供SDK接口,整体的框架图如下:1. ConnectivityService提供数据连接管理服务,负责管理Mobile,WIFI,BT,Ethernet几大类网络连接,同时提供VPN和Tethering服务。
workPolicyManagerService提供网络策略管理服务,NetworkPolicyManagerService维护网络使用策略,策略可以从一个策略文件读取(策略文件保存在系统目录下的netpolicy.xml 文件中)。
也可以通过NetworkPolicyManager对外提供的设置策略接口(setNetworkPolicies及setUidPolicy)进行设置,NetworkPolicyManagerService能够根据这些设置或从策略文件中读取的策略控制网络连接。
另外NetworkPolicyManagerService还具有动态调节网络连接限额及动态设置网络连接的功能,动态调节网络连接限额机制是通过INetworkStatsService访问NetworkStatsService服务获得上面设置或读取的策略匹配的网络连接类型的传输统计信息(NetworkPolicyManagerService采用NetworkTemplate进行网络连接类型的匹配),并根据这些信息生成有效的规则,并提交给ConnectivityService服务,并调用NetworkManagementService 的setInterfaceQuota函数对网络连接的带宽限额。
PC客户端与Android服务端的Socket同步通信

PC客户端与Android服务端的Socket同步通信(USB)收藏需求:1.一个android端的service后台运行的程序,作为socket的服务器端;用于接收Pc client 端发来的命令,来处理数据后,把结果发给PC client2.PC端程序,作为socket的客户端,用于给android手机端发操作命令难点分析:1.手机一定要有adb模式,即插上USB线时马上提示的对话框选adb。
好多对手机的操作都可以用adb直接作。
不过,我发现LG GW880就没有,要去下载个2.android默认手机端的IP为“127.0.0.1”3.要想联通PC与android手机的sokcet,一定要用adb forward 来作下端口转发才能连上socket.view plaincopy to clipboardprint?Runtime.getRuntime().exec("adb forward tcp:12580 tcp:10086");Thread.sleep(3000);Runtime.getRuntime().exec("adb forward tcp:12580 tcp:10086");Thread.sleep(3000);4.android端的service程序Install到手机上容易,但是还要有方法来从PC的client 端来启动手机上的service ,这个办法可以通过PC端adb命令来发一个Broastcast ,手机端再写个接收BroastcastReceive来接收这个Broastcast,在这个BroastcastReceive来启动servicepc端命令:view plaincopy to clipboardprint?Runtime.getRuntime().exec("adb shell am broadcast -a NotifyServiceStart");Runtime.getRuntime().exec("adb shell am broadcast -a NotifyServiceStart");android端的代码:ServiceBroadcastReceiver.javaview plaincopy to clipboardprint?package com.otheri.service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.util.Log;public class ServiceBroadcastReceiver extends BroadcastReceiver {private static String START_ACTION = "NotifyServiceStart";private static String STOP_ACTION = "NotifyServiceStop";@Overridepublic void onReceive(Context context, Intent intent) {Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"+ "ServiceBroadcastReceiver onReceive");String action = intent.getAction();if (START_ACTION.equalsIgnoreCase(action)) {context.startService(new Intent(context, androidService.class));Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"+ "ServiceBroadcastReceiver onReceive start end");} else if (STOP_ACTION.equalsIgnoreCase(action)) {context.stopService(new Intent(context, androidService.class));Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"+ "ServiceBroadcastReceiver onReceive stop end");}}}package com.otheri.service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.util.Log;public class ServiceBroadcastReceiver extends BroadcastReceiver {private static String START_ACTION = "NotifyServiceStart";private static String STOP_ACTION = "NotifyServiceStop";@Overridepublic void onReceive(Context context, Intent intent) {Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"+ "ServiceBroadcastReceiver onReceive");String action = intent.getAction();if (START_ACTION.equalsIgnoreCase(action)) {context.startService(new Intent(context, androidService.class));Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"+ "ServiceBroadcastReceiver onReceive start end");} else if (STOP_ACTION.equalsIgnoreCase(action)) {context.stopService(new Intent(context, androidService.class));Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"+ "ServiceBroadcastReceiver onReceive stop end");}}}5.由于是USB连接,所以socket就可以设计为一但连接就一直联通,即在new socket和开完out,in流后,就用个while(true){}来循环PC端和android端的读和写android的代码:view plaincopy to clipboardprint?public void run() {Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"+ "a client has connected to server!");BufferedOutputStream out;BufferedInputStream in;try {/* PC端发来的数据msg */String currCMD = "";out = new BufferedOutputStream(client.getOutputStream());in = new BufferedInputStream(client.getInputStream());// testSocket();// 测试socket方法androidService.ioThreadFlag = true;while (androidService.ioThreadFlag) {try {if (!client.isConnected()) {break;}/* 接收PC发来的数据*/Log.v(androidService.TAG, Thread.currentThread().getName()+ "---->" + "will read......");/* 读操作命令*/currCMD = readCMDFromSocket(in);Log.v(androidService.TAG, Thread.currentThread().getName()+ "---->" + "**currCMD ==== " + currCMD);/* 根据命令分别处理数据*/if (currCMD.equals("1")) {out.write("OK".getBytes());out.flush();} else if (currCMD.equals("2")) {out.write("OK".getBytes());out.flush();} else if (currCMD.equals("3")) {out.write("OK".getBytes());out.flush();} else if (currCMD.equals("4")) {/* 准备接收文件数据*/try {out.write("service receive OK".getBytes());out.flush();} catch (IOException e) {e.printStackTrace();}/* 接收文件数据,4字节文件长度,4字节文件格式,其后是文件数据*/byte[] filelength = new byte[4];byte[] fileformat = new byte[4];byte[] filebytes = null;/* 从socket流中读取完整文件数据*/filebytes = receiveFileFromSocket(in, out, filelength,fileformat);// Log.v(Service139.TAG, "receive data =" + new// String(filebytes));try {/* 生成文件*/File file = FileHelper.newFile("R0013340.JPG");FileHelper.writeFile(file, filebytes, 0,filebytes.length);} catch (IOException e) {e.printStackTrace();}} else if (currCMD.equals("exit")) {}} catch (Exception e) {// try {// out.write("error".getBytes("utf-8"));// out.flush();// } catch (IOException e1) {// e1.printStackTrace();// }Log.e(androidService.TAG, Thread.currentThread().getName()+ "---->" + "read write error111111");}}out.close();in.close();} catch (Exception e) {Log.e(androidService.TAG, Thread.currentThread().getName()+ "---->" + "read write error222222");e.printStackTrace();} finally {try {if (client != null) {Log.v(androidService.TAG, Thread.currentThread().getName()+ "---->" + "client.close()");client.close();}} catch (IOException e) {Log.e(androidService.TAG, Thread.currentThread().getName()+ "---->" + "read write error333333");e.printStackTrace();}}public void run() {Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"+ "a client has connected to server!");BufferedOutputStream out;BufferedInputStream in;try {/* PC端发来的数据msg */String currCMD = "";out = new BufferedOutputStream(client.getOutputStream());in = new BufferedInputStream(client.getInputStream());// testSocket();// 测试socket方法androidService.ioThreadFlag = true;while (androidService.ioThreadFlag) {try {if (!client.isConnected()) {break;}/* 接收PC发来的数据*/Log.v(androidService.TAG, Thread.currentThread().getName()+ "---->" + "will read......");/* 读操作命令*/currCMD = readCMDFromSocket(in);Log.v(androidService.TAG, Thread.currentThread().getName()+ "---->" + "**currCMD ==== " + currCMD);/* 根据命令分别处理数据*/if (currCMD.equals("1")) {out.write("OK".getBytes());out.flush();} else if (currCMD.equals("2")) {out.write("OK".getBytes());out.flush();} else if (currCMD.equals("3")) {out.write("OK".getBytes());out.flush();} else if (currCMD.equals("4")) {/* 准备接收文件数据*/try {out.write("service receive OK".getBytes());out.flush();} catch (IOException e) {e.printStackTrace();}/* 接收文件数据,4字节文件长度,4字节文件格式,其后是文件数据*/byte[] filelength = new byte[4];byte[] fileformat = new byte[4];byte[] filebytes = null;/* 从socket流中读取完整文件数据*/filebytes = receiveFileFromSocket(in, out, filelength,fileformat);// Log.v(Service139.TAG, "receive data =" + new// String(filebytes));try {/* 生成文件*/File file = FileHelper.newFile("R0013340.JPG");FileHelper.writeFile(file, filebytes, 0,filebytes.length);} catch (IOException e) {e.printStackTrace();}} else if (currCMD.equals("exit")) {}} catch (Exception e) {// try {// out.write("error".getBytes("utf-8"));// out.flush();// } catch (IOException e1) {// e1.printStackTrace();// }Log.e(androidService.TAG, Thread.currentThread().getName()+ "---->" + "read write error111111");}}out.close();in.close();} catch (Exception e) {Log.e(androidService.TAG, Thread.currentThread().getName()+ "---->" + "read write error222222");e.printStackTrace();} finally {try {if (client != null) {Log.v(androidService.TAG, Thread.currentThread().getName()+ "---->" + "client.close()");client.close();}} catch (IOException e) {Log.e(androidService.TAG, Thread.currentThread().getName()+ "---->" + "read write error333333");e.printStackTrace();}}6.如果是在PC端和android端的读写操作来while(true){}循环,这样socket流的结尾不好判断,不能用“-1”来判断,因为“-1”是只有在socket关闭时才作为判断结尾。