python学习:编写TCP服务器&UDP服务器

python学习:编写TCP服务器&UDP服务器


本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.

 

环境:

主机:WIN10

python版本:3.4

开发环境:pyCharm 5.0.2


说明:
项目需求,编写了TCP服务器和UDP服务器负责接收和转发数据。


源代码:

# 导入socket库:
import socket
import threading
# import time
import crc16

# 服务器配置
HOST = '0.0.0.0'
# 信令端口
PORT_CMD = 12800
# 语音端口
PORT_AUDIO = 12801
# 帧头长度
LEN_FRAME_HEAD = 16
# 接收超时时间,单位s
TIME_OUT_RECV = 60
# 接收最大帧长,单位字节
MAX_LEN_FRAME = 8192
# 最大连接数
MAX_CONNECT = 1024

# 设备类型
DEVICE_SERVER = 0x10
DEVICE_STUDENT = 0x11
DEVICE_TEACHER = 0x12

# 在线列表
List_Online_Cmd = []
List_Online_Audio = []
# crc工具
crc_tool = crc16.crc16()


def deal_cmd(sock, addr):
    '''
    信令处理

    :param sock:客户端端口
    :param addr:客户端地址
    :return:无
    '''

    # 断开连接标志
    flag_break = False

    print('客户端连接,地址:%s:%s...' % addr)
    # sock.send(b'Welcome!')
    while True:

        try:
            # 接收数据
            msg = sock.recv(MAX_LEN_FRAME)

            # 判断是否断开连接等错误
            if not msg:
                print('错误:空数据包,可能断开连接')
                flag_break = True
                break

            # 判断帧长是否大于帧头长度
            if len(msg) < LEN_FRAME_HEAD:
                print('错误:帧长为%d小于帧头长度%d' % (len(msg), LEN_FRAME_HEAD))
                continue
            # 判断开始标志是否正确
            if msg[0] != 0xc5 or msg[1] != 0x5c:
                print('错误:开始标志错误')
                continue
            # 判断帧长是否正确
            len_data = (msg[12] << 8) + msg[13]
            if len(msg) != len_data + LEN_FRAME_HEAD:
                print('错误:帧长错误,实际帧长%d,理论帧长%d' % (len(msg), len_data + LEN_FRAME_HEAD))
                continue
            # 判断CRC校验是否正确
            crc_get = (msg[14] << 8) + msg[15]
            crc_calc = crc_tool.createcrc(list(msg)[LEN_FRAME_HEAD:])
            if crc_get != crc_calc:
                print('错误:CRC校验错误,实际0x%x,计算0x%x' % (crc_get, crc_calc))
                continue

            # 处理数据
            # 判断是否是笔迹包
            cmd = (msg[4] << 8) + msg[5]
            if cmd == 27:
                # 数据转发
                msg_tx = bytearray(msg)
                msg_tx[3] = DEVICE_SERVER
                msg_tx[5] = 28
                for s in List_Online_Cmd:
                    # i.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
                    if s != sock:
                        s.send(msg_tx)
        except socket.timeout:
            print('连接客户端超时')
            flag_break = True
            break

    # 判断是否断开连接
    if flag_break:
        print('断开与客户端连接...')
        List_Online_Cmd.remove(sock)
        for s in List_Online_Audio:
            if sock.getpeername()[0] == s[0]:
                print('删除语音客户端%s,%s' % s)
                List_Online_Audio.remove(s)
                break
        sock.close()


def thread_socket_cmd():
    '''
    信令端口监听线程

    :return: 无
    '''

    # 监听信令端口:
    socket_cmd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket_cmd.bind((HOST, PORT_CMD))
    socket_cmd.listen(MAX_CONNECT)
    print('信令端口%d:开始监听...' % PORT_CMD)

    while True:
        # 接受一个新连接:
        sock_cmd, addr_cmd = socket_cmd.accept()
        sock_cmd.settimeout(TIME_OUT_RECV)
        List_Online_Cmd.append(sock_cmd)
        # print(sock_cmd)
        # print(sock_cmd.getpeername()[1])

        # 创建新线程来处理TCP连接:
        t = threading.Thread(target=deal_cmd, args=(sock_cmd, addr_cmd))
        t.start()


def thread_socket_audio():
    '''
    语音端口监听线程

    :return: 无
    '''

    # 监听语音端口
    socket_audio = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    socket_audio.bind((HOST, PORT_AUDIO))
    print('语音端口%d:开始监听...' % PORT_AUDIO)

    # while True:
    #     # 接收数据:
    #     data, addr = socket_audio.recvfrom(MAX_LEN_FRAME)
    #     # for s in List_Online_Cmd:
    #     #     if s.getpeername()[0] ==
    #     List_Online_Cmd.append(addr)
    #
    #     socket_audio.sendto(b'Hello' + data, addr)


    # 断开连接标志
    flag_break = False

    while True:
        # 接收数据:
        msg, addr = socket_audio.recvfrom(MAX_LEN_FRAME)
        # 判断信令在线列表中是否存在
        flag_exist = False
        for s in List_Online_Cmd:
            # print(s.getpeername()[0], addr[0])
            if s.getpeername()[0] == addr[0]:
                flag_exist = True
                break
        if not flag_exist:
            print('错误:IP不在信令列表中')
            continue
        if List_Online_Audio.count(addr) == 0:
            List_Online_Audio.append(addr)
            print('添加语音客户端%s,%s' % addr)

        # 判断帧长是否大于帧头长度
        if len(msg) < LEN_FRAME_HEAD:
            print('错误:帧长为%d小于帧头长度%d' % (len(msg), LEN_FRAME_HEAD))
            continue
        # 判断开始标志是否正确
        if msg[0] != 0xc5 or msg[1] != 0x5c:
            print('错误:开始标志错误')
            continue
        # 判断帧长是否正确
        len_data = (msg[12] << 8) + msg[13]
        if len(msg) != len_data + LEN_FRAME_HEAD:
            print('错误:帧长错误,实际帧长%d,理论帧长%d' % (len(msg), len_data + LEN_FRAME_HEAD))
            continue
        # 判断CRC校验是否正确
        crc_get = (msg[14] << 8) + msg[15]
        crc_calc = crc_tool.createcrc(list(msg)[LEN_FRAME_HEAD:])
        if crc_get != crc_calc:
            print('错误:CRC校验错误,实际0x%x,计算0x%x' % (crc_get, crc_calc))
            # continue

        # 处理数据
        # 判断是否是语音包
        cmd = (msg[4] << 8) + msg[5]
        if cmd == 10000:
            # 数据转发
            msg_tx = bytearray(msg)
            msg_tx[3] = DEVICE_SERVER
            msg_tx[4] = (10002 >> 8) & 0xff
            msg_tx[5] = 10002 & 0xff
            for s in List_Online_Audio:
                if s != addr:
                    socket_audio.sendto(msg_tx, s)


if __name__ == '__main__':
    print('服务器开始工作...')

    # 信令线程
    thread_cmd = threading.Thread(target=thread_socket_cmd)
    thread_cmd.start()

    # 语音线程
    thread_audio = threading.Thread(target=thread_socket_audio)
    thread_audio.start()

    # 等待线程结束
    thread_cmd.join()
    thread_audio.join()

你可能感兴趣的:(python)