-
Notifications
You must be signed in to change notification settings - Fork 0
/
server13_final.py
311 lines (283 loc) · 11.5 KB
/
server13_final.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
'''
开始写发送图片功能
写第三个服务器, 作为发送图片的缓存服务器
在另一个py文件pictureServer, 同时运行
代码没改动
'''
import socket
import threading
import queue
import json # json.dumps(some)打包 json.loads(some)解包
import time
import os
import os.path
import requests
def call_robot(url, apikey, msg):
data = { # 这个是在帮助手册上直接复制过来的,"url"=="https://www.kancloud.cn/turing/www-tuling123-com/718227"
# """与reqType在同一级的参数有:{
# reqType : 输入类型
# perception : 输入信息
# userInfo : 用户参数"""
"reqType": 0,
# '''# reqType为int类型,可以为空,
# 输入类型:{
# 0:文本(默认)
# 1:图片
# 2:音频
# }'''
"perception": { # perception为用户输入信息,不允许为空
# """
# perception参数中的参数有:{
# inputText : 文本信息
# inputImage : 图片信息
# inputMedia : 音频信息
# selfInfo : 客户端属性
# }
# 注意:输入参数必须包含inputText或inputImage或inputMedia,可以是其中的任何一个\n # 也可以是全部!
# """
# 用户输入文文信息
"inputText": { # inputText文本信息
"text": msg
},
# 用户输入图片url
"inputImage": { # 图片信息,后跟参数信息为url地址,string类型
"url": "https://cn.bing.com/images/"
},
# 用户输入音频地址信息
"inputMedia": { # 音频信息,后跟参数信息为url地址,string类型
"url": "https://www.1ting.com/"
},
# 客户端属性信息
"selfInfo": { # location 为selfInfo的参数信息,
"location": { # 地理位置信息
"city": "杭州", # 所在城市,不允许为空
"province": "浙江省", # 所在省份,允许为空
"street": "灵隐街道" # 所在街道,允许为空
}
},
},
"userInfo": { # userInfo用户参数,不允许为空
# """
# "userInfo包含的参数":{
# "apiKey" : {
# "类型" : "String",
# "是否必须" : "Y ",
# "取值范围" : "32位",
# "说明" : "机器人标识"
# }
# "userId" : {
# "类型" : "String",
# "是否必须" : "Y ",
# "取值范围" : "长度小于等于32位",
# "说明" : "用户唯一标识"
# }
# "gropId" : {
# "类型" : "String",
# "是否必须" : "N ",
# "取值范围" : "长度小于等于64位",
# "说明" : "群聊唯一标识"
# }
# "userIdName" : {
# "类型" : "String",
# "是否必须" : "N ",
# "取值范围" : "长度小于等于64位",
# "说明" : "群内用户昵称"
# }
# }
# """
"apiKey": "ee19328107fa41e987a42a064a68d0da", # 你注册的apikey,机器人标识,32位
"userId": "Brandon" # 随便填,用户的唯一标识,长度小于等于32位
}
}
headers = {'content-type': 'application/json'} # 必须是json
r = requests.post(url, headers=headers, data=json.dumps(data))
return r.json()
def chatServer():
IP = ''
PORT = 50007
que = queue.Queue() # 用于存放客户端发送的信息的队列
users = [] # 用于存放在线用户的信息 [conn, user, addr]
lock = threading.Lock() # 创建锁, 防止多个线程写入数据的顺序打乱
# 用于接收所有客户端发送信息的函数
def tcp_connect(conn, addr):
# 连接后将用户信息添加到users列表
user = conn.recv(1024) # 接收用户名
user = user.decode()
if user == 'no':
user = addr[0] + ':' + str(addr[1])
users.append((conn, user, addr))
print('新连接:', addr, ':', user, end='') # 打印用户名
d = onlines() # 有新连接则刷新客户端的在线用户显示
recv(addr, d)
try:
while True:
data = conn.recv(1024)
data = data.decode()
recv(addr, data) # 保存信息到队列
conn.close()
except:
print(user + ' 断开连接')
delUsers(conn, addr) # 将断开用户移出users
conn.close()
# 判断断开用户在users中是第几位并移出列表, 刷新客户端的在线用户显示
def delUsers(conn, addr):
a = 0
for i in users:
if i[0] == conn:
users.pop(a)
print('剩余在线用户: ', end='') # 打印剩余在线用户(conn)
d = onlines()
recv(addr, d)
print(d)
break
a += 1
# 将接收到的信息(ip,端口以及发送的信息)存入que队列
def recv(addr, data):
lock.acquire()
try:
que.put((addr, data))
finally:
lock.release()
# 将队列que中的消息发送给所有连接到的用户
def sendData():
while True:
if not que.empty():
data = ''
reply_text = ''
# list = []
message = que.get() # 取出队列第一个元素
if message[1] == '':
continue
if isinstance(message[1], str): # 如果data是str则返回Ture
for i in range(len(users)):
#user[i][1]是用户名, users[i][2]是addr, 将message[0]改为用户名
for j in range(len(users)):
if message[0] == users[j][2]:
print('this: message is from user[{}]'.format(j))
if '@Robot' in message[1] and reply_text == '':
msg = message[1].split(':;')[0]
reply = call_robot(url,apikey,msg)
reply_text = reply['results'][0]['values']['text']
data = ' ' + users[j][1] + ':' + message[1] + ':;' + 'Robot:' + '@' + users[j][1] + ',' + reply_text
break
elif '@Robot' in message[1] and (not reply_text == ''):
data = ' ' + users[j][1] + ':' + message[1] + ':;' + 'Robot:' + '@' + users[j][1] + ',' + reply_text
else:
data = ' ' + users[j][1] + ':' + message[1]
break
users[i][0].send(data.encode())
data = data.split(':;')[0]
if isinstance(message[1], list): # 同上
# 如果是list则打包后直接发送
data = json.dumps(message[1]) # dict -> str
for i in range(len(users)):
users[i][0].send(data.encode())
# 将在线用户存入online列表并返回
def onlines():
online = []
for i in range(len(users)):
online.append(users[i][1])
return online
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.bind( (IP, PORT) )
s.listen(5)
print('tcp server is running...')
q = threading.Thread(target=sendData)
q.start()
while True:
conn, addr = s.accept()
t = threading.Thread(target=tcp_connect, args=(conn, addr))
t.start()
s.close()
################################################################
def fileServer():
first = r'.\resources'
os.chdir(first) # 把first设为当前工作路径
IP = ''
PORT = 50008
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.bind( (IP, PORT) )
s.listen(3)
def tcp_connect(conn, addr):
print('Connected by: ', addr)
while True:
data = conn.recv(1024)
data = data.decode()
if data == 'quit':
print('Disconnected from {0}'.format(addr))
break
order = data.split()[0] # 获取动作
recv_func(order, data)
conn.close()
# 传输当前目录列表
def sendList():
listdir = os.listdir(os.getcwd())
listdir = json.dumps(listdir)
conn.sendall(listdir.encode())
# 发送文件函数
def sendFile(message):
name = message.split()[1] #获取第二个参数(文件名)
fileName = r'./' + name
with open(fileName, 'rb') as f:
while True:
a = f.read(1024)
if not a:
break
conn.send(a)
time.sleep(0.1) # 延时确保文件发送完整
conn.send('EOF'.encode())
# 保存上传的文件到当前工作目录
def recvFile(message):
name = message.split()[1] #获取文件名
fileName = r'./' + name
with open(fileName, 'wb') as f:
while True:
data = conn.recv(1024)
if data == 'EOF'.encode():
break
f.write(data)
# 切换工作目录
def cd(message):
message = message.split()[1] # 截取目录名
# 如果是新连接或者下载上传文件后的发送则 不切换 只将当前工作目录发送过去
if message != 'same':
f = r'./' + message
os.chdir(f)
path = ''
path = os.getcwd().split('\\') # 当前工作目录
for i in range(len(path)):
if path[i] == 'resources':
break
pat = ''
for j in range(i, len(path)):
pat = pat + path[j] + ' '
pat = '\\'.join(pat.split())
# 如果切换目录超出范围则退回切换前目录
if not 'resources' in path:
f = r'./resources'
os.chdir(f)
pat = 'resources'
conn.send(pat.encode())
# 判断输入的命令并执行对应的函数
def recv_func(order, message):
if order == 'get':
return sendFile(message)
elif order == 'put':
return recvFile(message)
elif order == 'dir':
return sendList()
elif order == 'pwd':
return pwd()
elif order == 'cd':
return cd(message)
while True:
conn, addr = s.accept()
t = threading.Thread(target=tcp_connect, args=(conn, addr))
t.start()
s.close()
apikey = 'ee19328107fa41e987a42a064a68d0da'
url = 'http://openapi.tuling123.com/openapi/api/v2'
serv1 = threading.Thread(target=chatServer)
serv1.start()
serv2 = threading.Thread(target=fileServer)
serv2.start()