Deploy a simple UDP service implemented by Python on CentOS (including MySQL database writing)

1 Python environment construction

Anaconda is a commonly used python package management program, which can set up multiple python environments.

  • Download the Anaconda installation script
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2021.05-Linux-x86_64.sh --no-check-certificate
  • After the download is complete, execute the installation, you will be prompted to read the authorization, just press Enter all the time
sh Anaconda3-2021.05-Linux-x86_64.sh

Then prompt you whether you agree, enter yes,
you will be asked about the installation location during the installation process, generally you don’t need to change it, just press Enter, it will automatically decompress
Finally, you will be prompted whether to initialize some configurations of Anaconda, remember to enter yes

  • After the installation is complete, configure Anaconda to the environment variable (if yes is selected during the initial configuration, this step should have been configured and can be skipped), and you can use the shortcut conda command
vim ~/.bashrc #编辑环境配置文件
export PATH="~/anaconda3/bin:$PATH" # 在第一行加入这个

Enter i in vim to edit, press Esc after editing, and then enter: wq to save the modification

  • After saving, update the environment variable and enter at the command line:
source ~/.bash_profile

Finally, verify whether the configuration is successful. If it is not saved, the configuration is successful!

  • After installation, create a python3.8 environment, execute the command, there will be a confirmation, enter y, and then press Enter
conda create --name ais_env python=3.8 --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
  • Activate the paddle_env environment
conda activate ais_env
  • Install the database support package pymysql
pip install pymysql

2 code upload

Upload the service code to the ais_server directory of the server, the file is as shown below:
insert image description here

ais_udp_server.py: UDP service code
database_mysql.py: database interface
test_client.py: test UDP client

2.1 ais_udp_server.py

# 这是 UDP 服务端
import socket
import datetime
import logging
from database_mysql import DataBaseMySQL


class MySqlDal:
    def __init__(self):
        self.db_mysql = DataBaseMySQL()

    def __del__(self):
        self.db_mysql.close()

    # 插入AIS原始数据
    def insert_ais_raw_data(self, type, data, parse_state, ct, mt):
        db = self.db_mysql
        str_sql = "INSERT INTO ais_raw_data (TYPE,DATA,parse_state,ct,mt) VALUES (%s,%s,%s,%s,%s)"
        return db.insert(str_sql, [type, data, parse_state, ct, mt])

    # 插入AIS动态数据
    def insert_ais_dynamic_data(self, raw_id, mmsi, lon, lat, speed, head_dir, track_dir, state, recv_time, ct):
        db = self.db_mysql
        str_sql = "INSERT INTO ais_dynamic_data (raw_id, mmsi, lon, lat, speed, head_dir, track_dir, state, " \
                  "recv_time, ct) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) "
        return db.insert(str_sql, [raw_id, mmsi, lon, lat, speed, head_dir, track_dir, state, recv_time, ct])

    # 插入AIS静态数据
    def insert_ais_static_data(self, raw_id, mmsi, ship_name, imo, call_no, ship_form, ship_draught, ship_length,
                               ship_width, destination, eta, recv_time, ct):
        db = self.db_mysql
        str_sql = "INSERT INTO ais_static_data (raw_id, mmsi, ship_name, imo, call_no, ship_form, ship_draught, " \
                  "ship_length, ship_width, destination, eta, recv_time, ct) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s," \
                  "%s,%s,%s) "
        return db.insert(str_sql,
                         [raw_id, mmsi, ship_name, imo, call_no, ship_form, ship_draught, ship_length, ship_width,
                          destination, eta, recv_time, ct])

    # 更新解析结果
    def update_ais_parse_state(self, id, state, mt):
        db = self.db_mysql
        str_sql = "UPDATE ais_raw_data SET parse_state = %s, mt = %s WHERE id = %s"
        return db.update(str_sql, [state, mt, id])


dal = MySqlDal()

# HOST_NAME = socket.gethostname()
# HOST = socket.gethostbyname(HOST_NAME)  # 主机号可为空白 HOST = ""
HOST = '0.0.0.0'    # 这里有个坑,服务ip需要写0.0.0.0,不能使用127.0.0.1,不然内网和外网其他机器都访问不了,只能本机访问该服务
PORT = 9504
ADDR = (HOST, PORT)  # 地址与端口
BUF_SIZE = 10240  # 接收数据缓冲大小
UDPSerSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 创建udp服务器套接字
UDPSerSock.bind(ADDR)  # 套接字与地址绑定-服务端特有
print(ADDR)
encodeing = "gb18030"
# encodeing = "utf-8"

while True:
    # 接收客户端发来的字节数组-此处监听
    data, addr = UDPSerSock.recvfrom(BUF_SIZE)  # 接收客户端发来的字节数组,data.decode()='char',data.upper()='bytes'
    data_str = data.decode(encodeing)
    print("{} Data Receive from Client {} --> {}".format(datetime.datetime.now(), addr, data_str))
    if data_str is None:
        response_str = "Error: Data is None!"
    elif not data_str.startswith("@"):
        response_str = "Error: Format error 1!"
    else:
        data_array = data_str.replace("@", "").strip(' ').split(",")
        if len(data_array) == 8:
            # 动态数据
            ret = dal.insert_ais_raw_data(1, data_str, 0, datetime.datetime.now(), datetime.datetime.now())
            if ret is not None:
                try:
                    raw_id = ret
                    mmsi = data_array[0]
                    lon = 0 if len(data_array[1].strip(" ")) == 0 else float(data_array[1].strip(" "))
                    lat = 0 if len(data_array[2].strip(" ")) == 0 else float(data_array[2].strip(" "))
                    speed = 0 if len(data_array[3].strip(" ")) == 0 else float(data_array[3].strip(" "))
                    head_dir = 0 if len(data_array[4].strip(" ")) == 0 else float(data_array[4].strip(" "))
                    track_dir = 0 if len(data_array[5].strip(" ")) == 0 else float(data_array[5].strip(" "))
                    state = 0 if len(data_array[6].strip(" ")) == 0 else int(data_array[6].strip(" "))
                    recv_time = 0 if len(data_array[7].strip(" ")) == 0 else int(data_array[7].strip(" "))
                    ret1 = dal.insert_ais_dynamic_data(raw_id, mmsi, lon, lat, speed, head_dir, track_dir, state, recv_time,
                                                datetime.datetime.now())
                    if ret1 is not None:
                        response_str = "Success!"
                        dal.update_ais_parse_state(raw_id, 1, datetime.datetime.now())
                    else:
                        response_str = "Error: Insert parse data error!"
                        dal.update_ais_parse_state(raw_id, -2, datetime.datetime.now())
                except Exception as e:
                    logging.error('数据解析失败:%s' % e)
                    response_str = "Error: Parse error!"
                    dal.update_ais_parse_state(raw_id, -1, datetime.datetime.now())
            else:
                response_str = "Error: Insert error!"
        elif len(data_array) == 11:
            # 静态数据
            ret = dal.insert_ais_raw_data(2, data_str, 0, datetime.datetime.now(), datetime.datetime.now())
            if ret is not None:
                try:
                    raw_id = ret
                    mmsi = data_array[0]
                    ship_name = data_array[1]
                    imo = data_array[2]
                    call_no = data_array[3]
                    ship_form = data_array[4]
                    ship_draught = 0 if len(data_array[5].strip(" ")) == 0 else float(data_array[5].strip(" "))
                    ship_length = 0 if len(data_array[6].strip(" ")) == 0 else float(data_array[6].strip(" "))
                    ship_width = 0 if len(data_array[7].strip(" ")) == 0 else float(data_array[7].strip(" "))
                    destination = data_array[8]
                    eta = 0 if len(data_array[9].strip(" ")) == 0 else int(data_array[9].strip(" "))
                    recv_time = 0 if len(data_array[10].strip(" ")) == 0 else int(data_array[10].strip(" "))
                    ret2 = dal.insert_ais_static_data(raw_id, mmsi, ship_name, imo, call_no, ship_form, ship_draught,
                                               ship_length, ship_width, destination, eta, recv_time,
                                               datetime.datetime.now())
                    if ret2 is not None:
                        response_str = "Success!"
                        dal.update_ais_parse_state(raw_id, 1, datetime.datetime.now())
                    else:
                        response_str = "Error: Insert parse data error!"
                        dal.update_ais_parse_state(raw_id, -2, datetime.datetime.now())
                except Exception as e:
                    logging.error('数据解析失败:%s' % e)
                    response_str = "Error: Parse error!!"
                    dal.update_ais_parse_state(raw_id, -1, datetime.datetime.now())
            else:
                response_str = "Error: Insert error!"
        else:
            response_str = "Error: Format error 2!"
    # 向客户端发送字节数组
    UDPSerSock.sendto(bytes(response_str, encodeing), addr)  # 向客户端发送字节数组, bytes("char", "utf-8")
    print("{} Response Sentend --> {}".format(datetime.datetime.now(), response_str))
    pass
UDPSerSock.close()  # 关闭服务端socket

2.2 database_mysql.py

import pymysql
import logging


class DataBaseMySQL:
    def __init__(self):
        try:
            self.connection = pymysql.connect(host="这里填写数据库服务器IP",
                                              user="这里填写用户名",
                                              pass删除这个word="这里填写PW",
                                              port=这里填写端口号,
                                              database="这里填写数据库名",
                                              charset='utf8')

            # "vn_vm_center"
            self.cursor = self.connection.cursor()
        except Exception as e:
            logging.error('数据库连接错误:%s' % e)
            raise

    def execute(self, sql):
        conn = self.connection
        try:
            cur = self.cursor
            cur.execute(sql)
            conn.commit()
            return True
        except Exception as e:
            logging.error('数据执行失败:%s' % e)
            conn.rollback()
            return False

    def query(self, sql, data):
        cur = self.cursor
        cur.execute(sql, data)
        res = cur.fetchone()
        return res

    def query_all(self, sql, data):
        cur = self.cursor
        cur.execute(sql, data)
        res = cur.fetchall()
        return res

    def insert(self, sql, data):
        conn = self.connection
        try:
            cur = self.cursor
            cur.execute(sql, data)
            res = conn.insert_id()
            conn.commit()
            return res
        except Exception as e:
            logging.error('数据新增执行失败:%s' % e)
            conn.rollback()
            return None

    def insert_many(self, sql, datas):
        conn = self.connection
        try:
            cur = self.cursor
            # 执行sql语句
            cur.executemany(sql, datas)
            # 提交到数据库执行
            conn.commit()
        except Exception as e:
            # 如果发生错误则回滚
            print(e)
            print(sql)
            print(datas)
            conn.rollback()
            logging.error('数据新增执行失败:%s' % e)

    def update(self, sql, data):
        conn = self.connection
        try:
            cur = self.cursor
            cur.execute(sql, data)
            conn.commit()
            return True
        except Exception as e:
            logging.error('数据更新执行失败:%s' % e)
            conn.rollback()
            return False

    def close(self):
        self.cursor.close()
        self.connection.close()

2.3 test_client.py

# 这是 UDP 客户端
import socket

HOST = '127.0.0.1'  # 本机测试
PORT = 9504  # 端口号
BUFSIZ = 10240  # 接收消息的缓冲大小
ADDR = (HOST, PORT)
print(ADDR)
UDPCliSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 创建客户端套接字
while True:
    ##step.1##
    data = input('输入发送内容> ')
    if not data:
        break
    UDPCliSock.sendto(bytes(data, 'gb18030'), ADDR)  # 由客户端向服务端发送【字节数组】
    ##step.2##
    data, ADDR = UDPCliSock.recvfrom(BUFSIZ)  # 接收服务端回应的【字节数组】
    if not data:  # 如果接收服务器信息失败,或没有消息回应
        break
    print('服务器:', ADDR, str(data, 'gb18030'))  # 打印回应消息
    pass
UDPCliSock.close()  # 关闭客户端socket

3 data sheet

3.1 ais_raw_data

insert image description here

3.2 ais_dynamic_data

insert image description here

3.3 ais_static_data

insert image description here

4 service running

  • Enter the code directory
cd /ais_server/
  • Enter the virtual environment
conda activate ais_env
  • run service
nohup python -u ais_udp_server.py > log.txt 2>&1 &

view progress

ps -ef|grep python

close process

kill -9 19913

view log

tail -f 1000 /ais_server/log.txt

How to Check Port Occupation

$: netstat -anp | grep 9504
udp        0      0 0.0.0.0:9504            0.0.0.0:*                           4793/python

Forcibly kill the process: by pid

$: kill -9 4793
$: netstat -anp | grep 8888

4 Test verification

The local test can be performed through the test_client.py client. Here, the SocketTool.exe tool is used for verification, as shown in the figure below:
insert image description here

Reference: https://blog.csdn.net/weixin_41275726/article/details/124529674

Guess you like

Origin blog.csdn.net/loutengyuan/article/details/130152499