python多线程及网络socket编程相关方法示例及总结

最近在学习python多线程和网络socket编程,以一个小的多线程socket程序作为练习,展示python多线程及网络socket编程的主要使用方法。

1、python多线程

    python多线程实现方式主要有三种:

  • 创建一个 Thread 的实例,传给它一个函数
  • 创建一个 Thread 的实例,传给它一个可调用的类对象
  • 从 Thread 派生出一个子类,创建一个这个子类的实例

其中,常用的方法为第一种和第三种。第一种方法实现相对简单,直接将待执行函数作为参数传递我给threading.Tread(target = func , args = ( XX,XX ))执行,其中target参数是即将在线程中执行的函数,args是函数参数。示例如下:

import threading

def add(x , y) :
    print(x + y)

t = threading.Thread(target=add , args=(1 , 2))
t.start()

第三种方法使用较为灵活,自定义线程类继承自threading.Thread类,并重写run方法即可,将线程需要执行的操作在run方法中实现,示例如下:

import threading

class MyThread(threading.Thread) :
    def run(self):
        print("my thread")

t = MyThread()
t.start()

使用自定义线程类定义聊天线程,其中重写Thread类的run方法控制线程执行:

#coding:utf-8
"""
    Created by cheng star at 2018/4/27 20:13
    @email : [email protected]
"""

import threading

"""
    使用threading.Thread 线程类创建聊天线程
"""
class ChatThread(threading.Thread) :
    def __init__(self , func , args , name = ""):
        threading.Thread.__init__(self)
        self.func = func    # 线程待执行的函数
        self.args = args    # 线程待执行函数的参数
        self.name = name    # 线程名

    def run(self) :
        # 执行线程
        self.res = self.func(*self.args)    # 使用可变长参数处理创建线程时传入的参数元组,

    def getResult(self):
        # 获取线程执行结果
        return self.res

if __name__ == "__main__" :
    pass

2、socket服务端开发

socket服务端开发基本流程:

  • 建立连接对象 socket.socket(socket.AF_INET , socket.SOCK_STREAM)
  • 绑定主机和端口 bind
  • 设置最大连接数 listen
  • 持续监听客户端连接
  • 建立通信线程进行处理,然后继续等待下一个连接到来 accept

以下代码基于第一节自定义的聊天线程实现服务器端的多线程:

#coding:utf-8
"""
    Created by cheng star at 2018/4/27 19:19
    @email : [email protected]
"""

import socket
from time import ctime
from DataAnalysisForPython.python_learning.python_threading_socket import chatThread
import sys

class TCPServer() :
    def __init__(self , host , port) :
        print("enter function >>>>>> %s" % sys._getframe().f_code.co_name)
        self.host = host
        self.port = port
        self.bufsize = 1024  # 设置缓冲区大小
        self.addr = (self.host , self.port) # 进行主机和端口时使用的参数(元组)

    def getTcpConnection(self):
        # 创建TCP连接对象
        print("enter function >>>>>> %s" % sys._getframe().f_code.co_name)
        self.tcpServer = socket.socket(socket.AF_INET , socket.SOCK_STREAM)  # 创建tcp连接对象
        self.tcpServer.bind(self.addr)    # 绑定主机和端口
        self.tcpServer.listen(5) # 设置允许的最大连接数

    def waitingConnection(self):
        print("enter function >>>>>> %s" % sys._getframe().f_code.co_name)
        # 等待客户端连接
        index = 1
        while True :
            print("waitting for connection ...")
            conn , addr = self.tcpServer.accept()   # 获取客户端连接返回的连接对象和连接地址,此连接对象用于和客户端交互
            print("connected from %s" %addr[0])
            ct = chatThread.ChatThread(self.chatting , (conn ,))    # 基于自定义线程类创建聊天线程,其中参数self.chatting是待执行的聊天处理函数,(conn ,)是参数元组,注意元组最后的逗号
            ct.start()  # 启动线程

    def chatting(self , conn) :
        # 聊天处理函数
        print("enter function >>>>>> %s" % sys._getframe().f_code.co_name)
        try :
            while True :
                data = conn.recv(self.bufsize).decode("utf8")   # 接受客户端发送的信息并进行转码
                print("server receive data %s" %data)
                if data.strip().lower() == "bye" :
                    # 判断是否结束聊天
                    break
                conn.send(("[%s] %s" %(ctime() , data)).encode("utf8")) # 服务端发送信息到客户端,已bytes数组格式发送
        except InterruptedError as e :
            pass
        except EOFError as e :
            pass
        except Exception as e :
            pass
        finally :
            print("close connection")
            conn.close()    # 断开当前tcp连接

    def tcpClose(self):
        print("enter function >>>>>> %s" % sys._getframe().f_code.co_name)
        self.tcpServer.close()

def main() :
    host = "localhost"
    port = 1234
    testChat = TCPServer(host , port)
    testChat.getTcpConnection()
    testChat.waitingConnection()

if __name__ == "__main__" :
    main()

3、socket客户端开发

socket客户端代码开发不用实现多线程,每个客户端即为一个线程,客户端只需要与服务端建立连接即可与服务端进行通信,与服务端建立连接的函数为connect,其参数与socket服务端bind函数参数相同,即为(主机、端口),连接建立后即可进行通信。服务端代码实现如下:

#coding:utf-8
"""
    Created by cheng star at 2018/4/27 19:41
    @email : [email protected]
"""
import socket
import sys

class TcpClient() :
    def __init__(self , host , port):
        print("enter function >>>>>> %s" %sys._getframe().f_code.co_name)
        self.host = host
        self.port = port
        self.bufsize = 1024
        self.addr = (self.host , self.port)

    def getTcpConnection(self):
        print("enter function >>>>>> %s" % sys._getframe().f_code.co_name)
        self.tcpClient = socket.socket(socket.AF_INET , socket.SOCK_STREAM)    # socket.SOCK_STREAM 建立TCP连接
        self.tcpClient.connect(self.addr)    # 通过执行主机地址和端口号与服务端建立连接

    def chatting(self):
        print("enter function >>>>>> %s" % sys._getframe().f_code.co_name)
        while True :
            data = input("> ").encode("utf8")
            if data.decode("utf8").strip().lower() == "bye" :
                break
            print(data)
            self.tcpClient.send(data)    # 发送信息到服务端

            recvData = self.tcpClient.recv(self.bufsize)    # 接受服务端的信息
            if recvData.decode("utf8").strip().lower() == "bye" :
                break
            print(recvData.decode("utf8"))

        self.tcpClient.close()    # 关闭客户端连接

def main() :
    host = "localhost"
    port = 1234
    tc = TcpClient(host , port)
    tc.getTcpConnection()
    tc.chatting()

if __name__ == "__main__" :
    main()

基于上述代码,首先运行服务端进行监听,然后分别启动三个客户端程序与客户端通信,三个客户端分别发送hello java,hello python,hello javascript字符串,服务端响应结果如下所示:

python多线程及网络socket编程相关方法示例及总结_第1张图片

以上分别简述了python threading模块多线程编程的常用方法及简单示例,并结合python socket网络编程实现多线程和网络编程的示例。

以上仅代表个人观点,谢谢!

参考文献:Python核心编程(中文第二版) Wesley J.Chun 著 CPUG 译

你可能感兴趣的:(python编程)