学习python网络通信的时候发现书上只有一个服务端对应一个客户端的情形,于是自己想自己动手实现一个服务端响应多个客户端。
1
2
3
|
tcpsersock = socket(af_inet,sock_stream) tcpsersock.bind(addr) tcpsersock.listen( 5 ) |
这样服务器的监听socket就建好了。
接下来的思路是,如果要监听多个客户端,则
1
|
tcpsersock.accept() #(accept()是阻塞式的) |
必须放进一个while循环(不放进循环监听一次就没了)。然而,这里就有问题了。如果按照一对一的那种处理顺序,客户端a连进来后,程序顺序向下执行,服务端要再写一个while循环,用来处理客户端a的请求,如果此时客户端b再来请求,服务器将接收不到。于是,很自然想到,将监听和处理放到不同的线程进行处理。我选择将监听放入主线程,将处理放进子线程。该服务器功能为接收到客户端的数据加上时间戳后返回给客户端。服务端完整代码如下:
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
|
#coding=utf-8 #!/usr/bin/env python ''''' author:mr.jing created on fri sep 22 14:29:03 2017 platfrom:win10,python2.7 ''' from socket import * from time import ctime import threading import time host = '' port = 2159 bufsiz = 1024 addr = (host,port) tcpsersock = socket(af_inet,sock_stream) tcpsersock.bind(addr) tcpsersock.listen( 5 ) socks = [] #放每个客户端的socket def handle(): while true: for s in socks: data = s.recv(bufsiz) if not data: socks.remove(s) continue s.send( '[%s],%s' % (ctime(), data)) #加上时间戳返回 t = threading.thread(target = handle) #子线程 if __name__ = = '__main__' : t.start() print u '我在%s线程中 ' % threading.current_thread().name #本身是主线程 print 'waiting for connecting...' while true: clientsock,addr = tcpsersock.accept() print 'connected from:' , addr socks.append(clientsock) |
两个客户端a和b同时连接,服务器输出:
可以看到服务端是可以相应多个客户端的。
客户端a发条消息试试?
服务器返回来了带时间戳的消息,goodjob。
那另一个呢?
很棒。服务器都能做出响应。
再发一条试试?
发现服务器没响应了,这是怎么回事呢?
经过仔细勘察发现是因为这句:
1
|
data = s.recv(bufsiz) |
因为recv方法是阻塞的,也就是说,当轮训到某个客户端,比如a,这句等待a发消息,不发消息就不往下走,所以此时b再去发消息的话服务器就收不到了。
那该怎么办呢?
很容易想到,将其设为非阻塞就好了。但上网找了好久,虽然找到可以用setblocking(0) 将套接字设为非阻塞,然而具体怎么用却很少有人讲清楚。查资料后终于搞明白,非阻塞的recv方法会继续向下执行,若超时得不到数据则会抛出异常。
修改后的代码如下:
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
41
42
43
44
|
#coding=utf-8 #!/usr/bin/env python ''''' author:mr.jing created on fri sep 22 14:29:03 2017 platfrom:win10,python2.7 ''' from socket import * from time import ctime import threading import time host = '' port = 2159 bufsiz = 1024 addr = (host,port) tcpsersock = socket(af_inet,sock_stream) tcpsersock.bind(addr) tcpsersock.listen( 5 ) socks = [] #放每个客户端的socket def handle(): while true: for s in socks: try : data = s.recv(bufsiz) #到这里程序继续向下执行 except exception, e: continue if not data: socks.remove(s) continue s.send( '[%s],%s' % (ctime(), data)) t = threading.thread(target = handle) #子线程 if __name__ = = '__main__' : t.start() print u '我在%s线程中 ' % threading.current_thread().name #本身是主线程 print 'waiting for connecting...' while true: clientsock,addr = tcpsersock.accept() print 'connected from:' , addr clientsock.setblocking( 0 ) socks.append(clientsock) |
此时再去尝试:
客户端随便输都会得到响应。任务达成!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/qq_34062683/article/details/78063035