Unix/Linux网络编程实验六:并发服务器之多线程【二】线程特定数据(python版)

线程特定数据的引出

单线程C程序有两类基本数据:局部数据和全局数据。

对于多线程C程序,添加了第三类数据:线程特定数据

那么为什么要引入线程特定数据呢?

试想如果你的一个线程里面嵌套调用了很多函数,而你又想在这些函数之间使用一个公共的变量,如果在单线程C中,我们是不是就要声明一个全局变量了呢?

是的。但是我们想使声明的这个全局变量只属于我们当前这个实例线程(同一个void *(*start_routine)(void *)可以实例化很多线程),其他的线程访问不到,故引入线程特定数据TSD。(ps:如果我们直接声明了一个全局变量,则其他线程也有可能使用到这个变量)。

线程特定数据的概念:

线程特定数据与全局数据非常相似,区别在于前者为线程所有。

(如果你学过面向对象编程,他们的关系就类似于class中静态成员与普通成员的关系。
所有对象都可以访问静态成员,而每个普通对象的普通成员只能被自己这个对象访问)

线程特定数据与python

通过查阅相关资料,博主我基于_thread_实现的threading官方文档,模块是python是实现多线程的内置库。

在官方文档的目录中,看到一级目录的Thread-Local Data。

**Thread-local data is data whose values are thread specific.
线程本地数据的值是线程特有的

**For more details and extensive examples, see the documentation string of the. threading local module.
更多的细节和例子,请到=查看_threading_ local模块的字符文档

threading官方文档

基于python的threading内置库的14-5实验的实现–使用_threading_ local

客户端程序

#client_c.py
import socket
import time
import queue
from threading import Thread

q = queue.Queue()

def recv_message(s):
    data = s.recv(1024).decode('utf-8').strip()
    print(data)
    Cli_name=input('Input your name:')
    s.send(Cli_name.encode('utf-8'))
    while True:
        data = input('\ninput Message:')
        s.send(data.encode('utf-8'))
        if data == 'exit':
            q.put(1)
            break
        data = s.recv(1024).decode('utf-8').strip()
        print(data)
    s.close()

try:
    s = socket.create_connection(('127.0.0.1', 12306))

    #recv_message(s)
    Thread(target=recv_message, args=(s,)).start()
    time.sleep(1)
    while q.empty():
        pass
except Exception as e:
    print(e)

服务端程序

import socket
from threading import Thread
import socketserver
import threading
from threading import get_ident

HOST = ''
POST = 12306
BUFSIZ = 1024
ADDR = (HOST, POST)
cli_data = threading.local()	#实例化线程本地数据对象


def message_handle(client):
    cli_data_ls=[]
    client.send('Server Message: Welcome to my server'.encode('utf-8'))
    cli_name = client.recv(1024).decode('utf-8')
    print('You got a connection from %s. Client name is %s'%(addr,cli_name))
    while True:
        data = client.recv(1024).decode('utf-8')
        #cli_data.msg=data
        #items=cli_data.msg
        #cli_data_ls.append(items)
        cli_data_ls.append(data)	#python语言实现14-5实现的效果并不一定要用到python中的线程本地数据,python中使用列表即可存储用户历史信息,但该列表是不是TSD,还有待实验验证
        print('Recieve Client (%s) Message: %s'%(cli_name,data))
        if data == 'exit':
            g_conn_pool.remove(client)
            client.send(data.encode('utf-8'))
            #print(cli_name+'下线了'+str(get_ident()),end='')
            cli_data.msg=cli_data_ls		#使用python中的线程本地数据对象 存储该线程的数据,其他线程无法访问该数据,但对该线程的所有函数是可访问的
            print(cli_data_ls)
            print(cli_data.msg)
            print(cli_data.__dict__)
            break
        data='Server Message:'+data[::-1]
        client.send(data.encode('utf-8'))

g_socket = None
g_conn_pool = []
try:
    g_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)	#创建SOCKET
    g_socket.bind(ADDR)
    g_socket.listen(5)	#参数5是侦听次数

    while True:
        client, addr = g_socket.accept()
        #print(addr)
        g_conn_pool.append(client)	#存储链接服务器的客户端的数量
        #message_handle(client)
        t = Thread(target=message_handle, args=(client,))	#实例化线程对象,参数target=message_handle表明该线程运行函数message_handle
        t.setDaemon(True)
        t.start()
except Exception as e:
    print(e)
print('exit')

服务端核心代码

函数主体中
t = Thread(target=message_handle, args=(client,))	#实例化线程对象,参数target=message_handle表明该线程运行函数message_handle
t.setDaemon(True)
t.start()

该代码初始引入了threading库中的Thread类,from threading import Thread

使用该类Thread可以实例化线程对象,参数target=message_handle表明该线程运行函数message_handle

message_handle 函数中

cli_data_ls.append(data) #python语言实现14-5实现的效果并不一定要用到python中的线程本地数据,python中使用列表即可存储用户历史信息,但该列表是不是TSD,还有待实验验证

cli_data.msg=cli_data_ls #使用python中的线程本地数据对象 存储该线程的数据,其他线程无法访问该数据,但对该线程的所有函数是可访问的

测试结果

测试结果

参考博客

Python 极简socket多人聊天群–CSDN 孤独暗星 2019-03-22 17:54:09

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值