python学习:编写TCP服务器&UDP服务器
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.
环境:
主机:WIN10
python版本:3.4
开发环境:pyCharm 5.0.2
源代码:
# 导入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()