【网络编程】socket编程(二)

socketserver模块介绍

socketserver内部使用IO多路复用以及“多线程”和“多进程”,从而实现并发处理多个客户端请求的socket服务端,即:每个客户端请求连接到服务器时,socket服务端都会在服务器是创建一个“线程”或者“进程”专门负责处理当前客户端的所有请求

基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环

python中socketserver模块将网络服务抽象成两个主要的类

① Server类:用于解决链接问题,并且提供两个Mixln类,用于扩展server,实现多进程或者多线程

② RequesHandlert类:用于解决通信问题,也就是处理数据相关的操作

Server类:

【网络编程】socket编程(二)_第1张图片

【网络编程】socket编程(二)_第2张图片

【网络编程】socket编程(二)_第3张图片

RequestHandler类:

【网络编程】socket编程(二)_第4张图片

继承关系:

【网络编程】socket编程(二)_第5张图片

【网络编程】socket编程(二)_第6张图片

 

【网络编程】socket编程(二)_第7张图片

TCP:

############## 服务端 ##############

import socketserver

class MyServer(socketserver.BaseRequestHandler):
    #通信
    #1.BaseRequestHandler找到__init__
    #def __init__(self, request, client_address, server):
        #self.request = request
        #self.client_address = client_address
        #self.server = server
        #self.setup()
        #try:
            #self.handle()
        #finally:
            #self.finish()
    #自定义handle方法
    def handle(self):
        print('conn is',self.request) #conn
        print('addr is',self.client_address) #addr

        while True: #通信循环
            try:
                #收消息
                data = self.request.recv(1024)
                if not data:break
                print('收到客户端信息是',data.decode('utf-8'))

                #发消息
                self.request.sendall(data.upper())
            except Exception as e:
                print(e)
                break

if __name__ == '__main__':
    s = socketserver.ThreadingTCPServer(('170.0.0.8',8030),MyServer) #多线程
    #s = socketserver.ForkingTCPServer(('170.0.0.8',8030), MyServer) #多进程
    #查找属性的顺序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer
    #链接
    #1-> class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass -->> 先ThreadingMixIn,然后TCPServer
    #2-> def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
        #BaseServer.__init__(self, server_address, RequestHandlerClass)
    #3->def __init__(self, server_address, RequestHandlerClass):
        #self.server_address = server_address
        #self.RequestHandlerClass = RequestHandlerClass
    #因此ThreadingTCPServer实例化传进去的参数分别为server_address和RequestHandlerClass

    print(s.server_address) #('170.0.0.8',8030)
    print(s.RequestHandlerClass) #
    print(MyServer) #
    print(s.socket) #
    s.serve_forever()
    #1.BaseServer中找到def serve_forever(self, poll_interval=0.5):
    #2.执行self._handle_request_noblock()
    #3.执行request, client_address = self.get_request() 就是TCPServer中的self.socket.accept()
       #然后执行self.process_request(request, client_address)
    #4.ThreadingMixIn中找到process_request,开启多线程应对并发,进而执行process_request_thread
    #5.最后self.finish_request(request, client_address)
    #上面完成链接循环,BaseServer中找到finish_request,触发我们自己定义的类的实例化,下一步通信

############## 客户端 ##############

from socket import *

ip_port = ('170.0.0.8',8030)
buffer_size = 1024

tcp_client = socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)

while True:
    msg = input('>>:').strip()
    if not msg:continue #输入的命令为空时,继续进行下一次循环(输入)
    if msg == 'quit':break #客户端断开连接

    tcp_client.send(msg.encode('utf-8'))

    data = tcp_client.recv(buffer_size)
    print('收到服务端发送的消息',data.decode('utf-8'))

tcp_client.close()

UDP:

################## 服务端 ##################
import socketserver

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request)
        print('收到客户端的消息是',self.request[0])
        self.request[1].sendto(self.request[0].upper(),self.client_address)

if __name__ == '__main__':
    s = socketserver.ThreadingUDPServer(('172.0.0.8',8050),MyServer) #多线程
    #s = socketserver.ForkingTCPServer(('172.0.0.8',8050), MyServer) #多进程
    #
    #1.在TCPServer找到BaseServer.__init__,在BaseServer找到self.server_address = server_address
        #self.RequestHandlerClass = RequestHandlerClass

    print(s.server_address) #('172.0.0.8',8050)
    print(s.RequestHandlerClass) #
    print(MyServer) #
    print(s.socket) #
    s.serve_forever()
    #1.self._handle_request_noblock()
    #2.request, client_address = self.get_request()
    #3.执行UDPServer中的get_request    data, client_addr = self.socket.recvfrom(self.max_packet_size)
     #得到return (data, self.socket), client_addr
    #结论
    #recvfrom的结果是((data,self.socket),client_addr) -->>self.get_request()得到的结果
    #request对应的是(data,self.socket) , client_addr对应的是client_address
    #有了socket对应的就是udp的套接字对象,可以调用sendto和recvfrom收发信息

################## 客户端 ##################

from socket import *

ip_port = ('172.0.0.8',8050)
buffer_size = 1024

udp_client = socket(AF_INET,SOCK_DGRAM)

while True:
    msg = input('>>:').strip()
    if not msg:continue
    if msg == 'quit':break
    udp_client.sendto(msg.encode('utf-8'),ip_port)

    data,addr = udp_client.recvfrom(buffer_size)
    print('收到服务端发送的消息',data.decode('utf-8'))

udp_client.close()

源码分析总结:

基于tcp的socketserver,我们自己定义的类中的:

① self.server即套接字对象:self.socket
② self.request即一个链接:conn
③ self.client_address即客户端地址:client_addr

基于udp的socketserver,我们自己定义的类中的:

① self.request是一个元组(第一个元素是客户端发来的数据:data,第二部分是服务端的udp套接字对象:self.socket)

② self.client_address即客户端地址:client_addr

 

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