如何建立"socket"连接?

Python010

如何建立"socket"连接?,第1张

一般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 {

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 {

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。否则只使用不释放,程序很 快就溢出了。

项目是基于MQTT,但重连逻辑被重写过。项目中会先请求LBS接口返回ip地址,再进行socket链接。

之前是只有一个LBS地址,失败之后内部重试链接。现在服务端会返回两个ip地址,第一个失败之后再进行第二个连接。

socket连接使用CFStreamCreatePairWithSocketToHost,超时由系统控制。

socket连接坏的IP地址,超时时间在75s,无法控制超时时间。

在[self.encoder open]时dispatch_after控制超时时间,如果在规定时间内没有回调,则认为ip连接失败。返回给上层,进行下一个ip连接。

源码阅读参考 MQTT源码阅读及问题分析

偶现socket未连接,复现概率比较低。只有结合日志,阅读源码。

突破点在于connectHandler这个block;为什么没有回调。