Добавил:
unit_man
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Курсовая / serverONE
.pyimport sys, socket, datetime, threading, os
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from GUI.server_gui import Ui_MainWindow # импорт сгенерированного файла
HOST = "127.0.0.1"
PORT = 5400
run = True # Флаг остановки дочерних потоков
servSocket = None
BUF_SIZE = 256 # Размер буфера сообшения
coords = [] # Координаты окна
lastRecv = [] # Последний запрос информации
movingStatus = 0 # произошла ли смена окна
# отправка сообщения клиенту через сокет
def sendToClient(answer, servSocket, addr):
''' Параметры:
- answer: ответное сообщение
- servSocket: сокет сервера для отправки сообщения
- addr: адрес клиента'''
try:
servSocket.sendall(answer.encode()) # Отправка ответа клиенту через сокет, предварительно закодировав его в байты
print(f"Отправлено: {answer} кому: {addr}") # вывод в консоль
window.addItem('Сервер: ', answer) # Метода addItem у объекта window для добавления информации о переданном сообщении
except ConnectionError:
print("Ошибка! Клиент отключился во время передачи сообщения!")
global run
run = False
# Обработка полученного сообщения
def threadFunc(servSocket, addr, window):
global lastRecv
curr = []
# Получение предыдущей информации
for item in lastRecv:
if (item[0] == addr): # Выводится сообщение о подключении клиента через print и метод window.addItem(), который обновляет интерфейс приложения.
curr = item
break
with servSocket:
answer = f'Клиент {addr} подключен'
print(answer)
window.addItem('Сервер: ', answer)# Выводится сообщение о подключении клиента через print и метод window.addItem(), который обновляет интерфейс приложения.
while run:
# Получение сообщения от Клиента
try:
# Получаем данные из соединения через сокет
data = servSocket.recv(BUF_SIZE).decode()
except ConnectionError:
print("Ошибка! Клиент отключился во время передачи сообщения!")
break
print(f"Получено: {data} от: {addr}")
if not data:
break
# Добавление времени в ответное сообщение
now = datetime.datetime.now()
answer = now.strftime("%d-%m-%Y %H:%M:%S")
answer += " получено"
# Если пришел запрос на вывод имен комьюетра и пользователя
if (data == 'send names'):
laptop_name = socket.gethostname() # Имя компьютера
user_name = os.getlogin() # Имя пользователя
data = f"\nИмя ноута: {laptop_name}\nИмя юзера: {user_name}"
window.addItem('Клиент: ', data)
answer += data
else:
# Если пришел запрос на изменение координат (-1 значит что если он ничего не нашел)
if(data.find(" x ") != -1):
new_coords = data.split(" x ")
# проверка на ввод (нельзя вводить дробные числа и не числа)
if (new_coords[0].lstrip('-').isdigit() and (new_coords[1].lstrip('-')).isdigit()):
# Проверка изменений
if(curr[1] != new_coords[0] or curr[2] != new_coords[1]):
curr[1] = new_coords[0]
curr[2] = new_coords[1]
# Отправляем сообщение
window.addItem('Клиент: ', data)
global coords
coords = data
# перемещаем окно
window.changeWindowPosition()
QThread.msleep(100)
# Проверка смены координат окна
global movingStatus
if(movingStatus == 1):
movingStatus = 0
answer += " x Смена координат: Успешно"
else:
answer += " x Смена координат: Ошибка x Неправильный формат координат. Введите целочисленные значения."
else:
# Введенные координаты не являются целыми числами
answer = " x Смена координат: Ошибка x Неправильный формат координат. Введите целочисленные значения."
# отправляем данные клиенту
sendToClient(answer, servSocket, addr)
answer = f'Клиент {addr} отключился'
print(answer)
window.addItem('Сервер: ', answer)
# Запуск сервера
def runServer():
'''socket.AF_INET - это константа, которая указывает на использование сокета семейства IPv4.
socket.SOCK_STREAM - это константа, которая указывает на использование потокового (TCP) сокета.
socket.SOL_SOCKET - это уровень сокета, который указывает, что опция применяется к сокету в целом.
socket.SO_REUSEADDR - это опция сокета, которая позволяет повторно использовать локальный адрес для привязки на серверной стороне,
даже если он все еще находится в состоянии TIME_WAIT после закрытия предыдущего соединения.
'''
global HOST, PORT
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as serv_sock:
serv_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Привязка сокета к указанному хосту (адресу) и порту
serv_sock.bind((HOST, PORT))
serv_sock.listen(1)
print("Сервер запущен")
try:
while True:
global servSocket
print("Ожидает подключения...")
# Принятие подключения от клиента, возвращается сокет клиента и его адрес
servSocket, addr = serv_sock.accept()
# Добавление информации о клиенте в список lastRecv
lastRecv.append([addr, 0, 0])
# Создание и запуск нового потока для обработки клиента
t = threading.Thread(target=threadFunc, args=(servSocket, addr, window))
t.start()
except KeyboardInterrupt:
print("Сервер остановлен!")
finally:
global run
# Установка флага run в False для остановки основного потока
run = False
serv_sock.close()
# Класс, необходимый для смены координат окна сервера
class generate_insert_frame(QThread):
threadSignal = pyqtSignal(str) # Создание сигнала для передачи строки
def __init__(self):
super().__init__()
# отправка сигнала и завершение работы потока
def run(self):
global coords
self.threadSignal.emit(coords) # Отправка сигнала со значением координат
self.msleep(100)
self.stop()
def stop(self):
self.quit() # Завершение работы потока
# Пользовательский интерфейс
class mywindow(QMainWindow):
def __init__(self):
super(mywindow, self).__init__()
self.ui = Ui_MainWindow() # Создание экземпляра пользовательского интерфейса
self.ui.setupUi(self) # Настройка пользовательского интерфейса
self.setWindowTitle("Сервер 1") # Установка заголовка окна
def changeWindowPosition(self):
# Механизм сигналов/слотов передает информацию в главный поток из дочернего
# так как moveWindow() работает только из главного потока
self.thread = generate_insert_frame() # Создание экземпляра потока
self.thread.threadSignal.connect(self.moveWindow)
self.thread.start()
def moveWindow(self):
global coords
# Разделение координат на отдельные значения
coords = coords.split(' x ')
# рпеобразование в целочисленный тип
coords[0] = int(coords[0])
coords[1] = int(coords[1])
# перемещение кона
self.move(coords[0], coords[1])
# функция-обработчик события перемещения окна
def moveEvent(self, e):
global movingStatus
# Установка статуса перемещения
movingStatus = 1
# Вызов родительского метода moveEvent()
super(mywindow, self).moveEvent(e)
def addItem(self, str, data):
self.ui.listWidget.addItem(str + data)
# Запуск сервера в главном потоке
if __name__ == '__main__':
# Проверка на запушенный экземпляр приложения
lockfile = QLockFile(QDir.tempPath() + '/server_1.lock')
# Попытка блокировки файла блокировки (чтобы мог запускаться только 1 экземпляр сервера)
if lockfile.tryLock(100):
app = QApplication(sys.argv)
window = mywindow()
# Создание и запуск потока сервера в отдельном потоке
serverThread = threading.Thread(None, runServer)
serverThread.start()
window.show()
# Завершение программы вместе с выполнением цикла событий приложения
sys.exit(app.exec_())
else:
print("Сервер 1 уже запущен!")
Соседние файлы в папке Курсовая