如何实现android和服务器长连接

如何实现android和服务器长连接,第1张

前言:现在的大多数移动端应用都有实时得到消息的能力,简单来说,有发送消息的主动权和接受消息的被动权。例如:微信,QQ,天气预报等等,相信好处和用户体验相信大家都知道吧。

提出问题:这种功能必须涉及client(客户端)和server(服务器),所以到底client如何和server实现实时连接通讯?

分析问题:这种功能实际上就是数据同步,同时要考虑手机本身、电量、网络流量等等限制因素,所以通常在移动端上有一下两个解决方案:

1.一种是定时去server查询数据,通常是使用HTTP协议来访问web服务器,称Polling(轮询);

2.还有一种是移动端和服务器建立长连接,使用XMPP长连接,称Push(推送)。

从耗费的电量、流量和数据延迟性各方面来说,Push有明显的优势。但是使用Push的缺点是:

对于客户端:实现和维护相对成本高,在移动无线网络下维护长连接,相对有一些技术上的开发难度。

对于服务器:如何实现多核并发,cpu作业调度,数量庞大的长连接并发维护等技术,仍存在开发难点。转载,仅供参考。

短连接

连接->传输数据->关闭连接

比如HTTP是无状态的的短链接,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。

具体就是:浏览器client发起并建立TCP连接 ->client发送HttpRequest报文 ->server接收到报文->server handle并发送HttpResponse报文给前端,发送完毕之后立即调用socket.close方法

->client接收response报文->client最终会收到server端断开TCP连接的信号->client 端断开TCP连接,具体就是调用close方法。

也可以这样说:短连接是指SOCKET连接后,发送接收完数据后马上断开连接。

因为连接后接收了数据就断开了,所以每次数据接受处理不会有联系。 这也是HTTP协议无状态的原因之一。

长连接

连接->传输数据->保持连接 ->传输数据->...........->直到一方关闭连接,多是客户端关闭连接。

长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。

HTTP在短链接和长连接上的选择:

HTTP是无状态的 ,也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。

如果客户端浏览器访问的某个HTML或其他类型的 Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话

HTTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持(貌似最新的HTTP1.1 可以显示的指定 keep-alive),但还是无状态的,或者说是不可以信任的。

如果浏览器或者服务器在其头信息加入了这行代码 Connection:keep-alive

TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了带宽。

实现长连接要客户端和服务端都支持长连接。

什么时候用长连接,短连接?

长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。

每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。

例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。

WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。

总之,长连接和短连接的选择要视情况而定。

一般socket链接有以下两种方式:长(常)链接和短链接。

长链接:当数据发送完成后socket链接不断开。一直保留到异常或者是程序退出为止 ,这种方式的好处是不用每次去发起连接断开,在速度上可以比短连接要快一些,但是相 对来说对服务器的资源压力也要大些。长链接用的范围很广,比如游戏系统,qq等等,长 (常)链接一般还需要定时向服务器ping数据,以保证socket链接畅通。当ping不通服务 器时,需要重新开启链接。

短链接:当一次数据发送完毕后,主动断开链接,每次发送数据都要一次链接、断开 操作,这种方式的好处是:对服务器的资源占用相对来说比较小,但是由于每次都要重新 链接,速度开销上也比较大,这种方式对于那种不需要经常与服务器交互的情况下比较适 用。

上面两种方法在用户量非常大的情况下都存在着很大的不足,因此,考虑可以用 一种折衷的办法,那就是使用socket的连接池。

程序一开始初始化创建若干数量的长链接。给他们设置一个标识位,这个标识位表示 该链接是否空闲的状态。当需要发送数据的时候,系统给它分配一个当前空闲的链接。同 时,将得到的链接设置为“忙”,当数据发送完毕后,把链接标识位设置为 “闲”,让系统可以分配给下个用户,这样使得两种方式的优点都充分的发挥 出来了。用户数量足够多的时候,只需要动态增加链接池的数量即可。

下面我们用具体的程序来讲解下:

首先声明一个socket类:

public class XieGouSocket

{

public Socket m_socket//Socket对象

public bool m_isFree//判断是否空闲

public int m_index//在链接缓存池中的索引值

}

下面的函数是创建socket链接池,这里为了使代码更加清晰,特地把异常处理部分 全部取掉了。

public XieGouSocket[] m_socket//先定义个缓冲池

public void CreateSocketPool()

{

string ip= “127.0.0.1”

string port= 2003

IPAddress serverIp=IPAddress.Parse(ip)

int serverPort=Convert.ToInt32(port)

IPEndPoint iep=new IPEndPoint(serverIp,serverPort)

m_socket = new XieGouSocket[200]

for(int i =0i <200 i ++)

{

m_socket[i] = new XieGouSocket()

m_socket[i].m_index = i

m_socket[i].m_isFree = true

m_socket[i].m_socket =new Socket (AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp)

m_socket[i].m_socket.SetSocketOption (SocketOptionLevel.Socket,SocketOptionName.SendTimeout,1000)

m_socket[i].m_socket.Connect(iep)

}

}

下面的函数是获取当前空闲的socket链接:

因为是多线程,所以需要加一个原子操作,定义一个原子变量,以防止多个线程 之间抢占资源问题的发生。

private static Mutex m_mutex=new Mutex()

public static XieGouSocket GetFreeConnection()

{

m_mutex.WaitOne()//先阻塞

for(int i =0i <m_socket.Length i ++)

{

if(m_socket[i].m_isFree) //如果找到一个空闲的

{

m_socket[i].m_isFree = false

m_mutex.ReleaseMutex()//释放资源

return m_socket[i]

}

}

//如果没有空闲的链接,要么等待,要么程序再动态创建一个链接。

m_mutex.ReleaseMutex()//释放资源

return null

}

当数据发送完毕后,程序必须将m_isFree 设置为 False。否则只使用不释放,程序很 快就溢出了。


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/244016.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-12
下一篇2023-04-12

发表评论

登录后才能评论

评论列表(0条)

    保存