伪SELECT版
server端
root@iZ947mgy3c5Z:/prodata/scripts# cat fake_select_tcp_server.py
import time
from socket import *
def main():
# 创建TCP Server套接字
server_socket = socket(AF_INET, SOCK_STREAM)
# 设置监听地址端口
server_port = ('127.0.0.1', 7788)
# 绑定地址端口
server_socket.bind(server_port)
# !!!setblocking这里是关键!!!
# 默认setblocking为True,也就accept时会阻塞住,但是这里没用多进程或多线程处理
# 所以如果主进程(主线程)被阻塞,也就意味着无法处理后面TCP连接
# 所以这里设置为False,也就是不阻塞
server_socket.setblocking(False)
# 设置半连接(正在三次握手的连接)和全连接(握手通过的连接)的队列长度
server_socket.listen(5)
# 客户端socket列表
client_socket_list = []
# 循环开始
while True:
# 异常处理为了捕获server套接字创建client套接字失败的情况
try:
client_socket, client_addr = server_socket.accept()
except Exception as e:
# 这就是创建失败抛出的异常,忽略即可
# [Errno 11] Resource temporarily unavailable
pass
else:
# 如果client套接字创建成功会将其socket对象append进client_socket_list中
# 以供后面for循环遍历检查是否socket是否有数据
client_socket_list.append(client_socket)
# 打印客户端连接上来信息
print('{}:{} connected...'.format(*client_addr))
# 循环遍历检查是否socket是否有数据
for cs in client_socket_list:
# 这里有点疑惑,这里印象中好像是会阻塞的,执行起来好像没发现阻塞
# 难道我之前设置server套接字非阻塞,所以它创建的client套接字也是非阻塞的?
# 接收客户端socket数据
client_data = cs.recv(1024)
# 如果数据长度小于等于0,说明客户端断开了连接
if len(client_data) <= 0:
# 从client_socket_list移除,不再检查
client_socket_list.remove(cs)
# 打印客户端断开信息
print('someone disconnect...')
else:
# 如果数据长度大于0,则说明客户端传过来数据了,所以打印时间和数据信息
print('[{}]: {}'.format(time.strftime("%Y-%m-%d %H:%M:%S"), client_data))
# 数据原封不动发回给客户端,模拟echo功能
cs.send(client_data)
# 这里sleep是为了减少CPU消耗,不然直接飙升到90多
time.sleep(0.1)
if __name__ == '__main__':
main()
client端
客户端很简单就是开了多线程来发数据
root@iZ947mgy3c5Z:/prodata/scripts# cat multi_thread_client.py
from socket import *
from multiprocessing import Pool, current_process
from threading import Thread, current_thread
import time
host_port = ('127.0.0.1', 7788)
def worker():
try:
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(host_port)
while True:
time.sleep(1)
client_socket.send('hi'.encode())
print('[{}]: {}'.format(time.strftime("%Y-%m-%d %H:%M:%S"), current_thread().name))
finally:
client_socket.close()
def main():
t1 = Thread(target=worker, name="t1")
t2 = Thread(target=worker, name="t2")
t3 = Thread(target=worker, name="t3")
t4 = Thread(target=worker, name="t4")
t1.start()
t2.start()
t3.start()
t4.start()
if __name__ == '__main__':
main()
执行效果
server
root@iZ947mgy3c5Z:/prodata/scripts# python3.5 fake_select_tcp_server.py
127.0.0.1:6917 connected...
[2018-01-24 09:39:01]: b'hi'
127.0.0.1:6918 connected...
[2018-01-24 09:39:02]: b'hi'
[2018-01-24 09:39:02]: b'hihi'
127.0.0.1:6919 connected...
[2018-01-24 09:39:03]: b'hi'
[2018-01-24 09:39:03]: b'hi'
[2018-01-24 09:39:03]: b'hihihi'
127.0.0.1:6920 connected...
[2018-01-24 09:39:04]: b'hi'
[2018-01-24 09:39:04]: b'hi'
[2018-01-24 09:39:04]: b'hi'
[2018-01-24 09:39:04]: b'hihihi'
[2018-01-24 09:39:05]: b'hi'
[2018-01-24 09:39:05]: b'hi'
[2018-01-24 09:39:05]: b'hi'
[2018-01-24 09:39:05]: b'hi'
[2018-01-24 09:39:06]: b'hi'
[2018-01-24 09:39:06]: b'hi'
[2018-01-24 09:39:06]: b'hi'
[2018-01-24 09:39:06]: b'hi'
client效果
root@iZ947mgy3c5Z:/prodata/scripts# python3.5 multi_thread_client.py
[2018-01-24 09:39:01]: t1
[2018-01-24 09:39:01]: t2
[2018-01-24 09:39:01]: t3
[2018-01-24 09:39:01]: t4
[2018-01-24 09:39:02]: t2
[2018-01-24 09:39:02]: t1
[2018-01-24 09:39:02]: t3
[2018-01-24 09:39:02]: t4
[2018-01-24 09:39:03]: t2
[2018-01-24 09:39:03]: t1
[2018-01-24 09:39:03]: t3
[2018-01-24 09:39:03]: t4
[2018-01-24 09:39:04]: t1
[2018-01-24 09:39:04]: t2
[2018-01-24 09:39:04]: t3
[2018-01-24 09:39:04]: t4
[2018-01-24 09:39:05]: t2
[2018-01-24 09:39:05]: t1
[2018-01-24 09:39:05]: t3
[2018-01-24 09:39:05]: t4
[2018-01-24 09:39:06]: t1
[2018-01-24 09:39:06]: t2
[2018-01-24 09:39:06]: t3
[2018-01-24 09:39:06]: t4
总结
关键点其实就几个
- 创建服务器套接字接受连接,但是注意千万不要让主线程被服务器套接字阻塞
- 获取可以读取的客户端套接字及数据
- 处理客户端套接字发送过来的数据