Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Курсовая / client

.py
Скачиваний:
0
Добавлен:
12.02.2024
Размер:
9.05 Кб
Скачать
import sys, socket, time, threading
from PyQt5 import QtWidgets
from GUI.client_gui import Ui_MainWindow  # импорт сгенерированного файла

HOST = "127.0.0.1"
PORT = [5400, 9999]

BUF_SIZE = 256 # Размер буфера для получения сообшения
clientSocket = [None, None]# Сокеты 
sockStatus = [0, 0]# Статусы подключения к серверам
reconnect = False# Флаг для переподключения при падении клиента
# Этот класс представляет главное окно приложения.
class mywindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(mywindow, self).__init__() #Вызов конструктора класса-родителя, QtWidgets.QMainWindow, для инициализации окна приложения.
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)# настраивает пользовательский интерфейс, определенный в классе Ui_MainWindow, и связывает его с текущим экземпляром главного окна.

        # Обработка нажатий кнопок
        self.ui.sendToServer_1.clicked.connect(self.send_coords_Button)
        self.ui.sendToServer_3.clicked.connect(self.send_names_Button)
        self.ui.sendToServer_4.clicked.connect(self.get_priority_Button)
        self.ui.sendToServer_2.clicked.connect(self.get_thread_id_Button)


    # Вспомогательная функция для проверки подключения перед отправкой
    def sendToServer(self, data, serverType):
        global clientSocket, sockStatus
        print(data)
        # Проверка типа сервера. Если тип равен 0, то следующий к первому серверу, в противном случае - ко второму серверу
        if(serverType == 0):
            self.ui.listWidget.addItem('Клиент: ' + data)
        else:
            self.ui.listWidget_2.addItem('Клиент: ' + data)

        # Если сервер уже подключен
        if(sockStatus[serverType] != 0):
            try:
                # Отправка данных на сервер с использованием соответствующего сокета
                clientSocket[serverType].sendall(data.encode())
                
            except OSError:
                data = 'Ошибка! Сервер не подключен!'
                print(data)
                sockStatus[serverType] = 0
                self.ui.listWidget.addItem('Клиент: ' + data)

        # Если сервер еще не подключен
        else:
            # Пробуем подключиться
            if(check_server(HOST, PORT[serverType]) == True):
                threading.Thread(None, runClient, args= [serverType]).start()

                time.sleep(0.5)
                self.send_coords_Button()

            # Если не удалось подключиться
            else:
                data = 'Ошибка! Сервер не подключен!'
                print(data)

                # Вывод в графический интерфейс
                self.ui.listWidget.addItem('Клиент: ' + data)

    # Отправка координат окна
    def send_coords_Button(self):
        if(len(self.ui.lineEdit.text()) > 0 and len(self.ui.lineEdit_2.text()) > 0):
            data = self.ui.lineEdit_2.text() + ' x ' + self.ui.lineEdit.text()
            self.ui.lineEdit.clear()
            self.ui.lineEdit_2.clear()

            self.sendToServer(data, 0)

    # Отправка имен компьютера и пользователя
    def send_names_Button(self):
        data = 'send names'
        self.sendToServer(data, 0)

    # Отправка запроса на получение приоритета процесса сервера
    def get_priority_Button(self):
        data = 'get process id'
        self.sendToServer(data, 1)

    # Отправка запроса на получение id потоков
    def get_thread_id_Button(self):
        data = 'get thread ids'
        self.sendToServer(data, 1)

    # Вывод текста в графический интерфейс
    def addItem(self, serverType, data):
        if(serverType == 0):
            self.ui.listWidget.addItem('Сервер: ' + data)
        else:
            self.ui.listWidget_2.addItem('Сервер: ' + data)

        print(data)

# Запуск клиента
def runClient(serverType): 
    global HOST, PORT, clientSocket, sockStatus
    is_started = False
    '''socket.AF_INET - это константа, которая указывает на использование сокета семейства IPv4.
    socket.SOCK_STREAM - это константа, которая указывает на использование потокового (TCP) сокета.
    socket.SOL_SOCKET - это уровень сокета, который указывает, что опция применяется к сокету в целом.
    socket.SO_REUSEADDR - это опция сокета, которая позволяет повторно использовать локальный адрес для привязки на серверной стороне, 
    даже если он все еще находится в состоянии TIME_WAIT после закрытия предыдущего соединения.
    ''' 
# Проверка возможности повторного подключения или на то, что клиент еще не запущен.
    while reconnect or not is_started:
        is_started = True
        print("\nКлиент создан")
        
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as clientSocket[serverType]:
            # устанавливает соединение с сервером
            clientSocket[serverType].connect((HOST, PORT[serverType]))
            sockStatus[serverType] = 1
            print(f"Сервер {serverType + 1} подключен")
            
            try:
                receiveFunc(serverType)

            except KeyboardInterrupt:
                print(f"Сервер {serverType + 1} отключен")
            
            finally:
                clientSocket[serverType].close()

# Получение сообщения
def receiveFunc(serverType):
    global clientSocket

    while True:
        # Получение ответа от сервера
        data_bytes = clientSocket[serverType].recv(BUF_SIZE)
        data = data_bytes.decode()
        # Если данные пусты
        if not data:
            print("Сервер закрыл соединение")
            break

        if(data.find(" x ") != -1):
            data = data.split(" x ")
            window.addItem(serverType, data[0])
            window.addItem(serverType, data[1])
        else:
            window.addItem(serverType, data)

# Проверка доступности сервера
def check_server(ip, port):
    '''socket.AF_INET - это константа, которая указывает на использование сокета семейства IPv4.
    socket.SOCK_STREAM - это константа, которая указывает на использование потокового (TCP) сокета.
    socket.SHUT_RDWR - это константа, которая указывает на полное закрытие (чтение и запись) соединения в сокете'''
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Создание сокета
    try:
        s.connect((ip, port)) # Подключение к серверу
        s.shutdown(socket.SHUT_RDWR) # Закрытие соединения
        return True
    except:
        return False
    finally:
        s.close()

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = mywindow() # Создание экземпляра класса mywindow

    # Подключение к серверу 1
    # Проверка доступности сервера 1
    if(check_server(HOST, PORT[0]) == True):
        # Запуск клиента в отдельном потоке для сервера 1
        threading.Thread(None, runClient, args= [0]).start() 

    # Подключение к серверу 2
    # Проверка доступности сервера 2
    if(check_server(HOST, PORT[1]) == True):
        # Запуск клиента в отдельном потоке для сервера 2
        threading.Thread(None, runClient, args= [1]).start()
    
    window.show()
    # Запуск основного цикла приложения
    sys.exit(app.exec_())
Соседние файлы в папке Курсовая