Day5

今日学习:

1.go语言学习

  学习Golang的意外收获:我写的代码执行效率超过了所有用户,哈哈哈

 

 

 

2.回顾Tcp

   在刚开始学习JAVA的时候,最让人头痛的就是,因为当时初学者刚学习,还没有养成编程思维,无法形象将文

件传输的操作比作在一个管道里传文件;但是现在写了很多行代码,对文件的传输比喻成流也能理解了。TCP,它的传输文件

也有recv和send:当服务器做send操作,那么客户端recv,就像管子的一段发送,另一端只能接收一样。

     那么问题来了,当客户端有多台的时候怎么办?不可能只靠一根管子,一个一个传给客户端吧?就在这里我们学习了线程池

一个服务器和每一台客户机都有一根管子;可是,就算是服务器和每个客户端之间都多了一根管子,有的客户端它老是不接收(或

发送)消息,我们不能老等着那些不去收发消息的客户端吧?所以,又在这时引入了阻塞/非阻塞的概念,服务端不用去等客户端到

底什么时候发消息过来,客户端要发消息过来叫一声,服务器就过去了(非阻塞

     但服务端不知道客户端每次发过来的消息是多少,一下长一下短的,其中就出现了将两次消息当作一次发过来的现象,粘包。

为了解决粘包现象,我们使用了包头[header],包头信息主要做的就是告诉服务端每一次接收多少消息。

   然而之前说的一台服务器和多个客户端之间有多个管子(多线程),在python里其实是不大可行的,因为python具有GIL锁,

如果你的电脑是双核CPU,就算开了多线程,它最多也就只能利用到一个核,多线程并没有什么帮助,虽然有很多管子,但是每次

只能用一个。然而回到最开始,服务器和多个客户端就算只有一个管子,那也足够了,当你还没准备好发送消息的时候(遇到IO阻塞

那我就把管子拿到别人那里去,最大限度的将管子的作用发挥到极限的方式,这种方式叫做协程,遇到IO跳过

     综上,TCP最终版可以成型了:

1.tcp服务端:

 1 import socket
 2 import threading
 3 import time
 4 
 5 
 6 class tcpServer:
 7     def __init__(self):
 8         self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 9         self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
10         self.client_socket_list = list()
11         self.port = 9527
12 
13     def tcp_server_start(self):
14         """
15         功能函数,TCP服务端开启的方法
16         :return: None
17         """
18         self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
19         self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
20         self.tcp_socket.setblocking(False)
21         try:
22 
23             self.tcp_socket.bind(('', self.port))
24         except Exception as ret:
25             self.msg = '请检查端口号\n'
26             print(self.msg)
27             print(ret)
28         else:
29             self.tcp_socket.listen()
30             self.sever_th = threading.Thread(target=self.tcp_server_concurrency)
31             self.sever_th.start()
32             self.msg = 'TCP服务端正在监听端口:%s\n' % str(self.port)
33             print(self.msg)
34 
35 
36     def tcp_server_concurrency(self):
37         """
38         功能函数,供创建线程的方法;
39         使用子线程用于监听并创建连接,使主线程可以继续运行,以免无响应
40         使用非阻塞式并发用于接收客户端消息,减少系统资源浪费,使软件轻量化
41         :return:None
42         """
43         while True:
44             try:
45                 self.client_socket, self.client_address = self.tcp_socket.accept()
46 
47             except Exception as ret:
48                 time.sleep(0.001)
49 
50             else:
51                 self.client_socket.setblocking(False)
52                 # 将创建的客户端套接字存入列表
53                 self.client_socket_list.append((self.client_socket, self.client_address))
54                 self.msg = 'TCP服务端已连接IP:%s端口:%s\n' % self.client_address
55                 print(self.msg)
56             # 轮询客户端套接字列表,接收数据
57             for client, address in self.client_socket_list:
58                 try:
59                     recv_msg = client.recv(1024)
60                 except Exception as ret:
61                     pass
62                 else:
63                     if recv_msg:
64                         msg = recv_msg.decode('utf-8')
65                         self.msg = '来自IP:{}端口:{}:\n{}\n'.format(address[0], address[1], msg)
66                         print(self.msg)
67                     else:
68                         client.close()
69                         self.client_socket_list.remove((client, address))
70     def tcp_server_send(self):
71         send_msg = input('')
72         for client, address in self.client_socket_list:
73             client.send(send_msg.encode('utf-8'))
74         self.msg = 'TCP服务端已发送\n'
75         print(self.msg)
76 
77 if __name__ == '__main__':
78     tcpS=tcpServer()
79     tcpS.tcp_server_start()
80     while True:
81         tcpS.tcp_server_send()
View Code

2.tcp客户端:

import socket
import threading


class TcpClient:
    def __init__(self):
        self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.ip="127.0.0.1"
        self.port=9527

    def tcp_client_start(self):
        """
        功能函数,TCP客户端连接其他服务端的方法
        :return:
        """
        self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            self.address = (str(self.ip), int(self.port))
        except Exception as ret:
            self.msg = '请检查目标IP,目标端口\n'
            print(self.msg)
        else:
            try:
                self.msg = '正在连接目标服务器\n'
                print(self.msg)
                self.tcp_socket.connect(self.address)
            except Exception as ret:
                self.msg = '无法连接目标服务器\n'
                print(self.msg)
                print(ret)
            else:
                self.client_th = threading.Thread(target=self.tcp_client_concurrency)
                self.client_th.start()
                self.msg = 'TCP客户端已连接IP:%s端口:%s\n' % self.address
                print(self.msg)

    def tcp_client_concurrency(self):
        """
        功能函数,用于TCP客户端创建子线程的方法,阻塞式接收
        :return:
        """
        while True:
            recv_msg = self.tcp_socket.recv(1024)
            if recv_msg:
                msg = recv_msg.decode('utf-8')
                self.msg = '来自IP:{}端口:{}:\n{}\n'.format(self.address[0], self.address[1], msg)
                print(self.msg)
            else:
                self.tcp_socket.close()
                self.msg = '从服务器断开连接\n'
                print(self.msg)
                break
    def tcp_client_send(self):
        send_msg = input('')
        self.tcp_socket.send(send_msg.encode('utf-8'))
        self.msg = 'TCP客户端已发送\n'

if __name__ == '__main__':
    tcpC = TcpClient()
    tcpC.tcp_client_start()
    while True:
        tcpC.tcp_client_send()
View Code

功能如下:

  -两端可以同时收发消息

  -非阻塞方式减少服务器压力

  -子线程用于监听并创建连接,使主线程可以继续运行,以免无响应

  -非阻塞式并发用于接收客户端消息,减少系统资源浪费

 


3.防优酷项目业务逻辑层学习:

  管理员业务需求抽取:

  -管理员:1.上传电影

       2.删除电影

       3.更新公告

 3.1 上传电影功能

  获取一个从客户端接受来的字典back_dict,

  1.从字典获取属性:名字,大小,是否免费,电影MD5码,上传者id

  2.根据电影名,使用tcp从客户端管理员获取电影,并存放于设定的好目录文件夹下

  3.对数据库进行更新,把刚才下好的电影信息进行保存

 

 3.2删除电影功能

  获取一个从客户端接受来的字典back_dict,

  1.从字典获取属性:需要删除的电影id

  2.从数据库中搜索出该电影,并返回一个相对应的电影对象

  3.对该电影的is_delete设置为1,1为已经删除

  4.对数据库进行更新,把刚才做好删除标记的电影信息进行保存

  

   3.3 更新公告功能

  获取一个从客户端接受来的字典back_dict,

  1.从字典获取属性:标题名称,内容,时间,管理员的id

  2.根据属性,获得对应的notice对象

  3.对内容进行保存

  4.对数据库进行更新,把刚才做好删除标记的电影信息进行保存

   

  业务层学习总结:

    1.业务层做的事是,向数据层获取数据,向界面层提交,实现需求。

  2.当业务层需要ORM做复杂一点的操作,例如多表查询,按需输出这,为了实现这些操作,需要向ORM里写一些新的获取数据层的手段方法,反而不利于开发效率吧?

  3.在细节上,例如判断上传的电影是否存在,那么根据select()返回一个对象,如果存在就返回一个对象;这样的操作会不会太臃肿?因为毕竟我只是需要知道它存在就行了

  4.在业务层上,conn始终作为一个参数参与进行业务实现,这样做会不会有什么风险问题?我可不可以将收发信息的功能写到lib里,使得业务逻辑层不直接与客户连接混在一起?

业务层管理员代码实现:

  

import datetime

import os

from conf import settings
from lib import common
from orm import models

#上传电影功能
# @common.login
def upload_movie_interface(back_dic):
    movie_size = back_dic.get('movie_size')
    movie_name = back_dic.get('movie_name')
    # movie_new_name = common.get_session(movie_name) + movie_name
    movie_new_name = movie_name
    movie_path = os.path.join(settings.DOWNLOAD_MOVIES_PATH, movie_new_name)
    # recv_data = 0
    # with open(movie_path, 'wb') as f:
    #     while recv_data < movie_size:
    #         data = conn.reader.read(100)
    #         f.write(data)
    #         recv_data += len(data)

    # 2.存储电影信息于电影表中
    movie_obj = models.Movie(
        name=movie_new_name,
        is_free=back_dic.get('is_free'),
        is_delete=0,
        file_md5=back_dic.get('movie_md5'),
        path=movie_path,
        create_time=str(datetime.datetime.now()),
        user_id=back_dic.get('user_id')
    )

    movie_obj = movie_obj.save()
    print(movie_obj.__dict__)
    # data = {'flag': True, 'msg': '电影上传成功!'}
    # conn.writer.write(data)

#删除电影
def delete_movie_interface(back_dic, ):
    movie_id = back_dic.get('movie_id')
    movie_obj = models.Movie.select(models.Movie(),whereStr="id={0}".format(movie_id))[0]
    print(movie_obj.is_delete)
    movie_obj.is_delete = 1  # 0 --> 1
    movie_obj.update()

    send_dic = {
        'flag': True,
        'msg': '电影删除成功!'
    }
    # common.send_msg(send_dic, conn)

#发送公告
def send_notice_interface(back_dic, ):

    notice_obj = models.Notice(
        title=back_dic.get('title'),
        content=back_dic.get('content'),
        create_time=str(datetime.datetime.now()),
        user_id=back_dic.get('user_id')
    )
    notice_obj = notice_obj.select(whereStr="movie_id={0}".format(notice_obj.user_id))[0]
    # 插入公告
    notice_obj.save()

    send_dic = {
        'msg': '公告发布成功!'
    }

    # common.send_msg(send_dic, conn)



back_dict={'movie_size':10,
           'movie_name':'盗梦空间',
           'is_free':'0',
            'movie_md5': '123456',
            "movie_id":2,
             'user_id':5
}
# upload_movie_interface(back_dict)
delete_movie_interface(back_dict)
# send_notice_interface(back_dict)

 

  

 

    

posted @ 2019-11-05 17:20  杨归元  阅读(230)  评论(0编辑  收藏  举报