This repository has been archived by the owner on Jun 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 72
/
server.py
374 lines (332 loc) · 13.7 KB
/
server.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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
import socket
import threading
import queue
import json # json.dumps(some)打包 json.loads(some)解包
import time
import os
import os.path
import requests
import sys
# IP = socket.gethostbyname(socket.getfqdn(socket.gethostname()))
IP = ''
PORT = 50007
apikey = 'ee19328107fa41e987a42a064a68d0da'
url = 'http://openapi.tuling123.com/openapi/api/v2'
que = queue.Queue() # 用于存放客户端发送的信息的队列
users = [] # 用于存放在线用户的信息 [conn, user, addr]
lock = threading.Lock() # 创建锁, 防止多个线程写入数据的顺序打乱
def call_robot(url, apikey, msg):
data = {
"reqType": 0,
"perception": {
"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用户参数,不允许为空
"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()
#####################################################################################
# 将在线用户存入online列表并返回
def onlines():
online = []
for i in range(len(users)):
online.append(users[i][1])
return online
class ChatServer(threading.Thread):
global users, que, lock
def __init__(self, port):
threading.Thread.__init__(self)
# self.setDaemon(True)
self.ADDR = ('', port)
# self.PORT = port
os.chdir(sys.path[0])
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# self.conn = None
# self.addr = None
# 用于接收所有客户端发送信息的函数
def tcp_connect(self, conn, addr):
# 连接后将用户信息添加到users列表
user = conn.recv(1024) # 接收用户名
user = user.decode()
for i in range(len(users)):
if user == users[i][1]:
print('User already exist')
user = '' + user + '_2'
if user == 'no':
user = addr[0] + ':' + str(addr[1])
users.append((conn, user, addr))
print(' New connection:', addr, ':', user, end='') # 打印用户名
d = onlines() # 有新连接则刷新客户端的在线用户显示
self.recv(d, addr)
try:
while True:
data = conn.recv(1024)
data = data.decode()
self.recv(data, addr) # 保存信息到队列
conn.close()
except:
print(user + ' Connection lose')
self.delUsers(conn, addr) # 将断开用户移出users
conn.close()
# 判断断开用户在users中是第几位并移出列表, 刷新客户端的在线用户显示
def delUsers(self, conn, addr):
a = 0
for i in users:
if i[0] == conn:
users.pop(a)
print(' Remaining online users: ', end='') # 打印剩余在线用户(conn)
d = onlines()
self.recv(d, addr)
print(d)
break
a += 1
# 将接收到的信息(ip,端口以及发送的信息)存入que队列
def recv(self, data, addr):
lock.acquire()
try:
que.put((addr, data))
finally:
lock.release()
# 将队列que中的消息发送给所有连接到的用户
def sendData(self):
while True:
if not que.empty():
data = ''
reply_text = ''
message = que.get() # 取出队列第一个元素
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])
for i in range(len(users)):
try:
users[i][0].send(data.encode())
except:
pass
def run(self):
self.s.bind(self.ADDR)
self.s.listen(5)
print('Chat server starts running...')
q = threading.Thread(target=self.sendData)
q.start()
while True:
conn, addr = self.s.accept()
t = threading.Thread(target=self.tcp_connect, args=(conn, addr))
t.start()
self.s.close()
################################################################
class FileServer(threading.Thread):
def __init__(self, port):
threading.Thread.__init__(self)
# self.setDaemon(True)
self.ADDR = ('', port)
# self.PORT = port
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.first = r'.\resources'
os.chdir(self.first) # 把first设为当前工作路径
# self.conn = None
def tcp_connect(self, 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] # 获取动作
self.recv_func(order, data, conn)
conn.close()
# 传输当前目录列表
def sendList(self, conn):
listdir = os.listdir(os.getcwd())
listdir = json.dumps(listdir)
conn.sendall(listdir.encode())
# 发送文件函数
def sendFile(self, message, conn):
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(self, message, conn):
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(self, message, conn):
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 'resources' not in path:
f = r'./resources'
os.chdir(f)
pat = 'resources'
conn.send(pat.encode())
# 判断输入的命令并执行对应的函数
def recv_func(self, order, message, conn):
if order == 'get':
return self.sendFile(message, conn)
elif order == 'put':
return self.recvFile(message, conn)
elif order == 'dir':
return self.sendList(conn)
elif order == 'cd':
return self.cd(message, conn)
def run(self):
print('File server starts running...')
self.s.bind(self.ADDR)
self.s.listen(3)
while True:
conn, addr = self.s.accept()
t = threading.Thread(target=self.tcp_connect, args=(conn, addr))
t.start()
self.s.close()
#############################################################################
class PictureServer(threading.Thread):
def __init__(self, port):
threading.Thread.__init__(self)
# self.setDaemon(True)
self.ADDR = ('', port)
# self.PORT = port
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# self.conn = None
os.chdir(sys.path[0])
self.folder = '.\\Server_image_cache\\' # 图片的保存文件夹
def tcp_connect(self, conn, addr):
while True:
data = conn.recv(1024)
data = data.decode()
print('Received message from {0}: {1}'.format(addr, data))
if data == 'quit':
break
order = data.split()[0] # 获取动作
self.recv_func(order, data, conn)
conn.close()
print('---')
# 发送文件函数
def sendFile(self, message, conn):
print(message)
name = message.split()[1] # 获取第二个参数(文件名)
fileName = self.folder + name # 将文件夹和图片名连接起来
f = open(fileName, 'rb')
while True:
a = f.read(1024)
if not a:
break
conn.send(a)
time.sleep(0.1) # 延时确保文件发送完整
conn.send('EOF'.encode())
print('Image sent!')
# 保存上传的文件到当前工作目录
def recvFile(self, message, conn):
print(message)
name = message.split(' ')[1] # 获取文件名
fileName = self.folder + name # 将文件夹和图片名连接起来
print(fileName)
print('Start saving!')
f = open(fileName, 'wb+')
while True:
data = conn.recv(1024)
if data == 'EOF'.encode():
print('Saving completed!')
break
f.write(data)
# 判断输入的命令并执行对应的函数
def recv_func(self, order, message, conn):
if order == 'get':
return self.sendFile(message, conn)
elif order == 'put':
return self.recvFile(message, conn)
def run(self):
self.s.bind(self.ADDR)
self.s.listen(5)
print('Picture server starts running...')
while True:
conn, addr = self.s.accept()
t = threading.Thread(target=self.tcp_connect, args=(conn, addr))
t.start()
self.s.close()
####################################################################################
if __name__ == '__main__':
cserver = ChatServer(PORT)
fserver = FileServer(PORT + 1)
pserver = PictureServer(PORT + 2)
cserver.start()
fserver.start()
pserver.start()
while True:
time.sleep(1)
if not cserver.isAlive():
print("Chat connection lost...")
sys.exit(0)
if not fserver.isAlive():
print("File connection lost...")
sys.exit(0)
if not pserver.isAlive():
print("Picture connection lost...")
sys.exit(0)