Python3:简单的服务器(socketserver + MySQL)

本文将用实例讲解使用Python3编写简单的服务器程序,实现socket网络编程与MySQL数据库连接。本文的目的在于对网上众多博文的总结,以及对socket编程和MySQL连接与操作的学习总结。 本文不会像众多博文那样,如同教科书一般,详细地讲解socketserver和pymysql模块中有什么东西、各自有什么用,而是实例中用到了什么就讲什么。至于模块的详细讲解与分析,可以看看其他的博文或者源码。

数据库连接与操作

class Database:
    def __init__(self, host, user, password, database):
        try:
            self.conn = pymysql.connect(host, user, password, database)
            self.cursor = self.conn.cursor
        except:
            print("Error: connect mysql error")

    def self_sql(self, sql):
        try:
            self.cursor.execute(sql)
            self.conn.commit()
            return self.cursor.fetchall()
        except:
            return -1

Python3使用pymysql模块实现MySQL数据库连接与操作,而Python2连接MySQL需要使用MySQLdb模块。使用pip安装:
pip3 install pymysql
使用前先import。
下面讲解上面的代码:
初始化函数init()需要传递的参数分别为数据库服务器的地址、账户、密码和库名。connect()连接数据库,返回一个Connection对象(有兴趣的可以翻翻源码),之后可以通过该对象的cursor来操作数据库。
在Database类中定义了一个self_sql()函数,参数sql为SQL语句,类型是字符串。execute()执行SQL;fetchall()会获得SQL执行返回的所有结果。若要只获得SQL执行返回的第一个结果,可用fetchone()。SQL执行返回的数据是元组,需要注意处理。

socketserver

class Server(socketserver.BaseRequestHandler):
    def __init__(self, request, client_address, server):
        self.request = request
        self.client_address = client_address
        self.server = server
        self.database = Database("localhost", "root", "123456", "shaking")
        print("[" + self.client_address[0] + "] " + "Connect database successfully.")

        try:
            self.handle()
        finally:
            print("[" + self.client_address[0] + "] " + "End service.")

    def handle(self):
        while True:
            receive = str(self.request.recv(1024), encoding="utf8").split('|')
            print(receive)
            if receive[0] == "11":
                self.login(receive)
            elif receive[0] == "01":
                self.game_result(receive)
            elif receive[0] == "000":
                self.top()
            elif receive[0] == "001":
                self.register(receive)
            else:
                break

    def login(self, receive):
        print("[" + self.client_address[0] + "] " + "Ask to login.")
        sql = "select strcmp('" + receive[2] + "', (select passwd from users where username ='" + receive[1] + "'));"
        if 0 == self.database.self_sql(sql)[0][0]:
            global users
            users[self.client_address[0]] = receive[1]
            print(users)
            self.request.sendall(bytes("1\n", encoding="utf8"))
            print("[" + self.client_address[0] + "] " + "Login successfully.")
        else:
            self.request.sendall(bytes("0\n", encoding="utf8"))
            print("[" + self.client_address[0] + "] " + "Fail to login.")

    def game_result(self, receive):
        print("[" + self.client_address[0] + "] " + "Game Result.")
        sql = "select score from users where username = '" + users[self.client_address[0]] + "';"
        if int(receive[1]) > self.database.self_sql(sql)[0][0]:
            sql = "update users set score = " + receive[1] + " where username = '" + users[self.client_address[0]] + "';"
            self.database.self_sql(sql)

    def top(self):
        print("[" + self.client_address[0] + "] " + "Ask for the Top.")
        sql = "select username, score from users order by score desc;"
        sends = self.database.self_sql(sql)
        for send in sends:
            print(send)
            self.request.sendall(bytes(send[0] + '|' + str(send[1]) + '\n', encoding="utf8"))
        self.request.sendall(bytes('0\n', encoding="utf8"))

    def register(self, receive):
        print("[" + self.client_address[0] + "] " + "Ask to register.")
        sql = "select username from users where username ='" + receive[1] + "';"
        if not self.database.self_sql(sql):
            sql = "insert into users(username, passwd) values('" + receive[1] + "', '" + receive[2] + "');"
            self.database.self_sql(sql)
            print("[" + self.client_address[0] + "] " + "Register successfully.")
            self.request.sendall(bytes("1\n", encoding="utf8"))
        else:
            print("[" + self.client_address[0] + "] "
                  + ' Fail to register: The name has already existed.')
            self.request.sendall(bytes("0\n", encoding="utf8"))

socketserver是socket编程中的高级模块,很多事情(比如bind、listen)已经封装好了。我们可以通过重写setup()、handle()、finish()三个函数来实现服务器的编成。它们分别对应的作用是在连接建立之前完成初始化工作、连接之后的工作、连接断开后的首尾工作。使用前需要导入socketserver模块。
这儿,在handle()中用一while循环实现多次数据传输。recv()用于接收数据,接收后转换为字符串便于处理。实例中,通过if-elif-else实现各功能的选择,也可以通过字典来实现switch的功能。sendall()用于发送数据。在发送的数据中,可以看到有换行符(’\n’),这是因为客户端(Android端)接收用的是readline()。

if __name__ == '__main__':
    socketserver.ThreadingTCPServer(("192.168.43.102", 9999), Server).serve_forever()

ThreadingTCPServer()是Threading和TCPServer的组合,从名字也能看出,是多线程和TCP服务器。虽然也不是很明白GIL锁对于Python的多线程有多大的影响,但是这儿使用多线程实现对多个客户端请求的响应。serve_forever()使得程序一直运行。

代码下载

你可能感兴趣的:(Python)