python多线程socket编程之多客户端接入,pythonsocket

asyncio模块是python之父写的模块,按说应该是靠谱的,python3.6版本定义为稳定版本。

python多线程socket编程之多客户端接入,pythonsocket

Python中实现socket通信的服务端比较复杂,而客户端非常简单,所以客户端基本上都是用sockct模块实现,而服务
端用有很多模块可以使用,如下:

图片 1

1、客户端

#!/usr/bin/env python
#coding:utf-8
'''
file:client.py
date:9/9/17 3:43 PM
author:lockey
email:[email protected]
desc:socket编程客户端,python3.6.2
'''
import socket,sys
HOST = '192.168.1.6'
PORT = 8998
ADDR =(HOST,PORT)
BUFSIZE = 1024

sock = socket.socket()
try:
 sock.connect(ADDR)
 print('have connected with server')

 while True:
  data = input('lockey# ')
  if len(data)>0:
  print('send:',data)
  sock.sendall(data.encode('utf-8')) #不要用send()
  recv_data = sock.recv(BUFSIZE)
  print('receive:',recv_data.decode('utf-8'))
  else:
  sock.close()
  break
except Exception:
 print('error')
 sock.close()
 sys.exit()

2、SocketServer模块

为了能够让多个客户端同时接入服务并进行通信,服务端将使用SocketServer模块来实现,这样的话用户不用在子线程结束后,利用父进程对它进行处理,也不用关心socket的关闭,一切都由SocketServer来完成。

#!/usr/bin/env python
#coding:utf-8
'''
file:client.py
date:9/9/17 3:43 PM
author:lockey
email:[email protected]
desc:socket编程服务器端,python3.6.2
'''
from socketserver import BaseRequestHandler,ThreadingTCPServer
import threading

BUF_SIZE=1024

class Handler(BaseRequestHandler):
 def handle(self):
  address,pid = self.client_address
  print('%s connected!'%address)
  while True:
   data = self.request.recv(BUF_SIZE)
   if len(data)>0:
    print('receive=',data.decode('utf-8'))
    cur_thread = threading.current_thread()
    #response = '{}:{}'.format(cur_thread.ident,data)
    self.request.sendall('response'.encode('utf-8'))
    print('send:','response')
   else:
    print('close')
    break

if __name__ == '__main__':
 HOST = '192.168.1.6'
 PORT = 8998
 ADDR = (HOST,PORT)
 server = ThreadingTCPServer(ADDR,Handler) #参数为监听地址和已建立连接的处理类
 print('listening')
 server.serve_forever() #监听,建立好TCP连接后,为该连接创建新的socket和线程,并由处理类中的handle方法处理
 print(server)

以下测试中我使用另外一台主机和本机的两个中断去连接服务器,都可以正常连接并且能进行数据应答交互

图片 2

注意:此程序示例运行平台为rhel7.2.x86_64,python版本为3.6.2,对于windows平台和非同一python版本的用户可能缺乏一定的兼容性,如果是其他平台用户请自行修正!!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持帮客之家。

Python中实现socket通信的服务端比较复杂,而客户端非常简单,所以客户端基本上都是用so…

之前我们学了很多进程间的通信,多进程并发等等,今天我们来学习线程,线程和进程是什么关系,进程和线程有什么相同而又有什么不同今天就来揭晓这个答案。

说明书:

 

大概定义:该模块提供了使用协程编写单线程并发代码,通过套接字和其他资源复用I​​
/ O访问,运行网络客户端和服务器以及其他相关原语的基础结构。

本篇导航:

简单应用(基于wsgi的报警器)

  • 线程概论
  • python的并发编程之多线程
  • Python GIL(Global Interpreter
    Lock)
 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # @Time    : 2018/8/21 10:40
 4 # @Author  : WangYue
 5 # @Site    : 
 6 # @File    : alertor_uwsgi.py
 7 # @Software: PyCharm
 8 
 9 #加入环境变量避免程序报错
10 import sys,os
11 sys.path.append(os.path.dirname(os.path.dirname(__file__)))
12 
13 #引入wsgi模型,这里主要是弄一个简单的http模型来说明asyncio的简单使用
14 from wsgiref.simple_server import make_server
15 
16 #引入asyncio
17 import asyncio
18 
19 #引入其他可能的依赖
20 from threading import Thread
21 import json
22 
23 #引入本程序其他的内容,与asyncio无关是程序业务的其他部分
24 from conf.alertor_conf import ALERTOR_CONFIG
25 from model.alert_method_class import SendMail
26 
27 #定义一个运行asyncio loop 的线程,去单独运行它
28 def start_loop(loop):
29     asyncio.set_event_loop(loop)
30     loop.run_forever()
31 new_loop = asyncio.new_event_loop() #这个new_loop将会用于运行异步程序
32 t = Thread(target=start_loop, args=(new_loop,))
33 t.start() #利用多线程,额外起一个线程运行asyncio loop然后它在自身使用协程之类处异步处理业务
34 
35 
36 #这是wsgi主业务程序,application是wsgi的入口程序,wsgi就规定了这么个函数名,这样写wsgi就认可它是入口了。传参也是wsgi的规定,第一个是环境,第二个是响应
37 def application(env,start_res):
38     res_headers=[('Content-type', 'text/plain')]
39     if env["REQUEST_METHOD"]=='POST':
40         # the environment variable CONTENT_LENGTH may be empty or missing
41         try:
42             if env['PATH_INFO'] != "/send_alert":
43                 status = "404 func is not in use"
44                 start_res(status, res_headers)
45                 return [b"func is not in use"]
46 
47             request_body_size = int(env.get('CONTENT_LENGTH', 0))
48             status = "200 OK"
49             request_body = env['wsgi.input'].read(request_body_size)
50             print("post_info -->", request_body.decode())
51             r_body=json.loads(request_body.decode())
52             #就这里一行代码,new_loop.call_soon_threadsafe(),告诉asyncio去运行第一个参数的函数名,后边的参数是被运行函数的传参,有多少就传参多少个,这是异步的,非阻塞的。
53             new_loop.call_soon_threadsafe(SendMail.sendEmail,"Alertor Alarm level:"+r_body["level"]+"  server: "+r_body["server"],r_body)
54             start_res(status,res_headers)
55             return [b"ok send alert......."]
56         except (ValueError):
57             status = "404 json data not found key"
58             request_body_size = 0
59             start_res(status, res_headers)
60             return [b"get post info faild"]
61 
62     else:
63         status = "403 method error"
64         start_res(status,res_headers)
65         return [b'method error']
66 
67 # 1、只接受POST请求。数据为json格式,json中标记的,包括但不限于,包括的信息将会入库,其他信息,在告警时会一并发出
68 # {
69 #     "level":"high", #告警级别,"high","medium","info",这个可以在配置文件中配置,配置信息是个列表,有序的从左至右为["high","medium","info"],对应后续告警逻辑及post中json的本字段。
70 #     "@timestamp":"",#告警时间
71 #     "server":"",#告警源,可以是ip,主机名,服务名等可标识的
72 #     "message":""#具体的告警信息
73 # }
74 # 2、根据json中的level自动选择告警途径,选择方式,在配置文件中的alert_method字典信息
75 # 3、将告警内容,存储数据库,便于日后查询
76 # 4、后续提供查询统计告警信息的方法
77 
78 
79 if __name__=="__main__":
80     wsgi_server=make_server(ALERTOR_CONFIG['bind_ip'],ALERTOR_CONFIG['port'],application)
81 
82     wsgi_server.serve_forever()

 

目前这里先这么用,这个模型的性能是基于uwsgi运行,2进程,每个进程内4个线程,基准性能是15000请求总量,5000客户端

一、线程概论

 ab -n 15000-c 5000 -p test_alert.txt -T
application/x-www-form-urlencoded “”

1、何为线程

效果还凑合吧。

每个进程有一个地址空间,而且默认就有一个控制线程。如果把一个进程比喻为一个车间的工作过程那么线程就是车间里的一个一个流水线。

进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。

多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间(资源)

创建进程的开销要远大于线程开进程相当于建一个车间,而开线程相当于建一条流水线。

2、线程和进程的区别

1.Threads share the address space of the process that created it; processes have their own address space.
2.Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
3.Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
4.New threads are easily created; new processes require duplication of the parent process.
5.Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
6.Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.

中译:

1、线程共享创建它的进程的地址空间;进程有自己的地址空间。
2、线程可以直接访问其进程的数据段;进程有它们自己的父进程数据段的副本。
3、线程可以直接与进程的其他线程通信;进程必须使用进程间通信来与兄弟进程通信。
4、新线程很容易创建;新进程需要复制父进程。
5、线程可以对同一进程的线程进行相当大的控制;进程只能对子进程执行控制。
6、对主线程的更改(取消、优先级更改等)可能会影响该进程的其他线程的行为;对父进程的更改不会影响子进程。

3、多线程的优点

多线程和多进程相同指的是,在一个进程中开启多个线程

1)多线程共享一个进程的地址空间(资源)

2)
线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用

3)
若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。

4)
在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)


 

二、python的并发编程之多线程

1、threading模块介绍

multiprocessing模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍

对multiprocessing模块也不是很熟悉的朋友可以复习一下多线程时介绍的随笔:

30、进程的基础理论,并发(multiprocessing模块):

官方文档:(英语好的可以尝试挑战)

2、开启线程的两种方式(和进程一模一样)

两种方式里我们都有开启进程的方式可以简单复习回顾

1)方式一:

from threading import Thread
#from  multiprocessing  import  Process
import os
def talk():
    print('%s is running' %os.getpid())

if __name__ == '__main__':
    t=Thread(target=talk)
    # t=Process(target=talk)
    t.start()
    print('主',os.getpid())

2)方式二:

#开启线程
from threading import Thread
import os
class MyThread(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        print('pid:%s name:[%s]is running' %(os.getpid(),self.name))

if __name__ == '__main__':
    t=MyThread('lln')
    t.start()
    print('主T',os.getpid())

#开启进程
from multiprocessing import Process
import os
class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        print('pid:%s name:[%s]is running' % (os.getpid(), self.name))
if __name__ == '__main__':
    t=MyProcess('lll')
    t.start()
    print('主P',os.getpid())

3、在一个进程下开启多个线程与在一个进程下开启多个子进程的区别

1)比较速度:(看看hello和主线程/主进程的打印速度)

from threading import Thread
from multiprocessing import Process
import os

def work():
    print('hello')

if __name__ == '__main__':
    #在主进程下开启线程
    t=Thread(target=work)
    t.start()
    print('主线程/主进程')

    #在主进程下开启子进程
    t=Process(target=work)
    t.start()
    print('主线程/主进程')
You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图