前言

在解释 WebSocket 之前,先来看个生活中的小例子。

比如外汇股票,由多人组成的公司,上市就有股份,每人一个股份10块钱,随着公司盈利,股票升值,如果亏损,股票贬值, 股市中只能买张不能买跌,在股票交易时间内,股票的价格变化十分迅速,股票网站需要向正在浏览页面的用户实时更新股价 ,所以k线图每分钟都要绘制,用户可以根据k线图预测是涨还是跌,如果张就买入,跌就不买,我们要把每分钟的点连起来。

还有心电图,心电图每秒都要绘制,把每个点连起来,就形成了曲线图。

websocket的特点是持久化链接,实时化,一次强链接,实时,主动推送数据,websocket前后端可以同时推送,而http是一次请求。websocket长连接不是一对一的。

在我们发送请求时,要监控newtwork,网页newtwork中websocket304 200 意味着这次链接结束 500在这里表示成功,也意味着结束。websocket 101 表示链接成功。

下面我们来完成一个websocket测试。

写一个websocket接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#webscoket接口

clients = {}
@accept_websocket
def webscoketlink(request):

if request.is_websocket():
token = request.GET.get('user_id')

userid = jwt.decode(token,settings.SECRET_KEY,algorithms=['HS256']).get('user_id')

print('----------------------------------------------------------------------userid',userid)

while True:

message = request.websocket.wait()

if not message:
break
else:
print('webscoket链接成功' + str(message)) # 也可以用format

clients[userid] = request.websocket

if redis.get(userid):
msg = redis.get(userid).decode()
request.is_websocket.send(msg.encode('utf-8'))
redis.delete(userid)

# 推送消息
def sendmessage(request):

# 获取消息
msg = request.GET.get("msg")

for client in clients:
clients[client].send(msg.encode('utf-8'))

return HttpResponse({'OK'})

在这里不需要return,我们平时写接口return表示结束返回数据,断开连接,而websocket不用断开连接,但是没有网也不行,偶尔网络波动,连上网之后,它可以立刻连上,有持久化可能性,继续回去找userid,而http断开之后,回去不找userid。

前端如何操作

在home首页实现长连接,可以实时通知用户,每个网页写入组件,在页面加载之前连接websocket,判断浏览器是否支持websocket。为什么有的响应在前端打印,有的在后端打印,我们的链接的请求或关闭,不需要让客户知道,只要在后台默默的操作就好了,可是如果审核通过或者拒绝就需要让客户知道。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
mounted:function(){
判断浏览器是否支持webscoket
if("WebSocket" in window){

console.log('支持');
var ws = new WebSocket("ws://localhost:8000/webscoketlink/")

ws.onopen = function(){

ws.send("test")
}




//发送消息
ws.onmessage = function(evt){


//将获取信息打印 那个是提示 通知提醒
var received_msg = evt.data

alert(received_msg);

}

//捕获关闭链接
ws.onclose = function(){

console.log("链接已经关闭")
}

}

}

所有的实时通信都是基于websocket。

这块我们为什么用http协议,因为这是一个接收消息的接口,请求这个接口,然后去调用websocket然后返回给前端。

1
2
path('webscoketlink/', webscoketlink),
path('sendmessage/', sendmessage),

然后重启项目,状态码101 请求连接成功。

我们要写一个需求,就是用户如果不在线,怎么让他上线后收到推送消息,就是向指定用户发送websocket消息并处理对方不在线的情况。

  • 如果申请人在线(客户端与服务器正常链接)直接将消息推送即可。如果不在线(客户端与服务端没有链接)将数据在redis中以集合类型储存
  • 当每个用户首次与服务端链接时首先判断该用户在redis中有没有数据,如果有数据,直接遍历发送,客户端以弹窗形式提醒用户

    使用redis时需要注意:用这种消息推送,只需要用户作为键,不需要别的数据作为标识。

十种方式拼接Python字符串

字符串是所有编程语言中都有的基本变量的类型,程序员基本每天都在和字符串打交道。

本篇文章的最后我们一起细数Python中的各种字符串拼接方法。每种字符串拼接方式的使用场景各不相同,我们可以在开发过程中灵活运用。

一、用逗号,拼接

1
2
3
str_a = 'python'

print('hello', str_a, '!')

运行结果:

1
hello python !

用逗号拼接的结果中,相邻的两个字符串之间会有空格。

二、空格自动拼接

1
2
3
str_b = 'It is summer ' 'of 2019!'

print(str_b)

运行结果:

1
It is summer of 2019!

空格自动拼接后,两个字符串之间的空格不会保留,两个字符串会直接连在一起,不能通过多个变量名来拼接。

三、多行字符串自动拼接

1
2
3
4
5
6
7
str_c = 'Love makes ' \

'man grow up ' \

'or sink down!'

print(str_c)

运行结果:

1
Love makes man grow up or sink down!

多行字符串之间会有反斜杠\作为连接,自动拼接后,多行字符串会直接连在一起,中间没有空格,不能通过多个变量名来拼接。

所以我们在编程中,一行写不完的字符串可以换行,最后的结果是一样的。

四、通过加号+拼接

1
2
3
4
5
6
7
8
9
str_d = 'string'

str_e = 'demo'

print(str_d + str_e)

str_e += str_d

print(str_e)

运行结果:

1
2
3
stringdemo

demostring

加号拼接的结果也是两个字符串直接拼接在一起,中间没有空格。

五、通过乘法*进行拼接

1
2
3
str_f = 'a-' * 10

print(str_f)

运行结果:

1
a-a-a-a-a-a-a-a-a-a-

Python中一个字符串与整数相乘的结果为字符串拼接整数次。

六、字符串格式化操作符%拼接

1
2
3
4
5
6
7
8
9
10
11
str_g = 'aaaaaaaaaaaa%saaaaaaaaa' % 'A'

print(str_g)

str_h = 'aaaaaaaaaaaa%06daaaaaaaaa' % 10

print(str_h)

str_i = 'aaaaaaaaaaaa%.03faaaaaaaaa' % 0.77

print(str_i)

运行结果:

1
2
3
4
5
aaaaaaaaaaaaAaaaaaaaaa

aaaaaaaaaaaa000010aaaaaaaaa

aaaaaaaaaaaa0.770aaaaaaaaa

%s,%d,%f的作用是占位作用,然后在字符串后面跟一个%,再在后面写拼到占位位置的内容。

%s:将一个字符串拼接到前面的字符串中

%d:将一个整型数字转换成字符串拼接到前面的字符串中,可以设置整数的位数,前面补0

%f:将一个浮点型数字转换成字符串拼接到前面的字符串中,可以设置小数点后的位数,后面补0

七、通过str.format()方法拼接

1
2
3
4
5
6
7
str_j = 'python {}! format {}!'.format(666, 999)

print(str_j)

str_k = '生如夏花之{a},死如秋叶之{b}!'.format(b='静美', a='绚烂')

print(str_k)

运行结果:

1
2
3
python 666! format 999!

生如夏花之绚烂,死如秋叶之静美!

format()方法可以说是最通用(基本是万能的)的拼接方法了,不管后面拼接的数据是字符串还是数字,甚至元组、列表、字典、集合等数据类型,format统统都可以拼接到字符串中。

在要拼接的字符串中使用大括号{}来给拼接内容占位,后面按顺序依次传入对应的内容即可,也可以给每个占位的{}起一个变量名,然后通过关键字参数传递给format().

八、通过str.join()方法拼接

1
2
3
4
5
6
7
8
9
10
11
list_l = ['生', '如', '夏', '花', '之', '绚', '烂', ',', '死', '如', '秋', '叶', '之', '静', '美', '!']

str_l = ''.join(list_l)

print(str_l)

tuple_m = ('生', '如', '夏', '花', '之', '绚', '烂', ',', '死', '如', '秋', '叶', '之', '静', '美', '!')

str_m = '-'.join(tuple_m)

print(str_m)

运行结果:

1
2
3
生如夏花之绚烂,死如秋叶之静美!

生-如-夏-花-之-绚-烂-,-死-如-秋-叶-之-静-美-!

str.join()最常用来将一个列表内的字符串拼接成一个大的字符串,列表中的每个元素都需要是字符串类型。

前面的str是拼接时用于连接的字符串,列表的每两个元素之间使用str来连接。

九、通过string模块中的Template对象拼接

1
2
3
4
5
6
7
from string import Template

t = Template('${s1} ${s2}!')

str_n = t.safe_substitute(s1='Hello', s2='Python')

print(str_n)

运行结果:

1
Hello Python!

Template的实现方式是首先通过Template初始化一个字符串对象t,在创建对象t时,在字符串中使用 ${变量名} 的方式来给拼接内容占位。

也可以省略{},直接 $变量名,只是没有{}时变量名后面一定要有空格,且可读性不如有{}的好。

通过调用t对象的substitute或safe_subsititute方法,将拼接内容通过关键字参数的方式依次传递进去,实现在指定的位置拼接字符串。

这种方法与上面的format()方法一样,不管传入的拼接内容是什么数据类型,统统都可以拼接。

十、通过F-strings拼接

1
2
3
4
5
6
7
o = 6666666666

p = 7777777777

str_o = f'Python {o} hello {p} !'

print(str_o)

运行结果:

1
Python 6666666666 hello 7777777777 !

在Python3.6版本中,提出了一种新型字符串格式化机制,被称为“字符串插值”或者F-strings,F-strings提供了一种明确且方便的方式将python表达式嵌入到字符串中来进行格式化。而且F-strings的运行速度很快,比%和format()这两种格式化方法都快得多。

上面的代码中直接在f后面跟字符串,然后在字符串中用{}传入拼接内容。

厉害的是,在F-strings中我们可以执行函数:

1
2
3
4
5
6
7
8
9
def add_string(str):

return str.upper()

str = 'a k q j 10'

str_p = f'顺子! {add_string(str)}'

print(str_p)

运行结果:

1
顺子! A K Q J 10

将函数传入{}中,最后拼接到字符串中的内容是函数执行的结果!

现在我们已经细数了十种Python字符串的拼接方式,希望您可以在使用中融会贯通,灵活运用。