连接在多个线程之间如何保证安全?

连接在多个线程之间如何保证安全?

比如使用 http 长连接,一个全局变量 g_http_conn

线程 a 在此连接上发出 request A,再收到 response A 之前,

线程 b 又使用该连接发出 request B。此时接受 response 会不会串了?

可能 Response A 先接受到,也可以是 Response B 先接受到。怎么判断接受到的 response 应该分发给 A 还是 B

同样的问题,Mysql 的长连接、redis 的长连接?

我想到的解决问题就是:

  • 加锁,不允许并发
  • 使用 TLS 或者连接池,来避免多线程共用同一个连接

但是如果就是想多线程共用一个连接,并且不想加锁呢?

不加锁的意思是:不对整个发出 request 到接受 response 的整个过程加锁,但是可以在发出 request 和接受 response 的过程加锁
不能这样:

with lock:

send_request()

rev_response()

但是可以这样

with lock:

send_request()

do_something()

with lock:

rev_response()


回答:

你好!看到这个问题后,我觉得蛮有意思,想基于自己学过的知识和你一起探讨一下这个问题。

首先,你说的response分发问题实际上Http2.0已经帮忙处理了。

可以从你说的办法出发,依次来看看HTTP2.0究竟是如何实现的。

一、不允许并发

对整个发起请求——等待返回的过程加锁,可以保证request-response顺序性,即每发起一个request,其他要发起的request等待,这样就能保证不乱序。

如果使用的是HTTP1.0,压根不需要自己在客户端去加锁。

因为HTTP1.0已经做了这个事情,即每次发送一个http请求就新建一个TCP连接。显然这样性能很低。由此有了HTTP1.1。

二、连接复用和连接池

这里的连接池需要强调一下,并不应该是http的连接池,而是TCP的连接池。因为HTTP是无连接的,实际上你问题中说的http长连接也是不准确的说法,本质上是基于TCP的长连接,可以把TCP连接想象成马路,http只是一封封邮件,必须要有路才能把邮件送到,当一开始没有路的时候就先修路(TCP三次握手)。
HTTP1.1为了解决1.0的性能问题,HTTP1.1 支持了keep-alive,只要请求或响应头带上 Connection: keep-alive,就可以告诉对方先不要断开TCP链接,实现了TCP的复用。”
但这只是解决了频繁“修路”的问题,还没有解决可以并发发送Request的问题。
于是HTTP1.1还给出了管道的概念,多个请求可以并行发送,返回响应后再依次处理,这里就是用到了TCP的连接池。
注意是依次处理,因为HTTP1.0还没解决request-response的一一对应的功能。

三、HTTP2.0

为了解决一一对应的问题,它给request设置一个id,response通过id就能找到发送它的人(线程)。
至于是怎么做的呢?这个回答怕是很难解释清楚,可以去维基百科等网站去查询HTTP2.0的Stream和Frame概念。

四、补充

我是一名后端开发,在看一些RPC(比如DUBBO)的实现上时,看到远程调用返回结果怎么找到发起请求的线程,也是用的这种id的机制。

以上是 连接在多个线程之间如何保证安全? 的全部内容, 来源链接: utcz.com/p/938456.html

回到顶部