SSL Socket Python неблокирующий - PullRequest
       27

SSL Socket Python неблокирующий

0 голосов
/ 22 октября 2019

Я установил связь клиент-сервер на python3. Он работает хорошо, сервер может обслуживать более одного клиента, все имеют openssl-import и используют многопоточность.

То, что я хочу сейчас: они должны иметь возможность использовать openSSL, и при получении чего-либо на сокете (сервер И клиент) они должны иметь возможность отправлять что-то, ПОЛУЧАЯ получение данных (например, вызов «count» от клиентаи после этого наберите что-нибудь еще при получении ответа). Но когда я запускаю свой код, каждый раз (при получении на стороне клиента), когда я хочу отправить что-либо, он в конце концов распознает то, что я пытался отправить. Трудно объяснить (мой английский не самый лучший). Что я делаю неправильно? Должен ли я сделать все сокеты в "неблокирующем режиме"? Может быть, вы можете проверить это:

сервер:

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::#
#::::::::::::::::::::::::::::::::::::        MULTITHREAD + SSL       ::::::::::::::::::::::::::::::::::::::::::#
#::::::::::::::::::::::::::::::::::::::::::::: [ server.py ] ::::::::::::::::::::::::::::::::::::::::::::::::::#
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::#
#TODO: logs, try-exp

import socket as socketlib
import ssl
from threading import Thread
from time import ctime #formatiertes datetime nutzen!
import logging
import time


HOST = '127.0.0.1'
PORT = 4200

AUTHENTICATIONS = {'fin': 'finja',
                   'haxe': '1337',
                   'hell': 'd404559f602eab6fd602ac7680dacbfaadd13630335e951f097af3900e9de176b6db28512f2e000b9d04fba5133e8b1c6e8df59db3a8ab9d60be4b97cc9e81db'
                   }

logging.basicConfig(filename="log.log", level=logging.DEBUG,
                    format='[%(levelname)s] %(asctime)s - %(name)s :  - LINE_%(lineno)s (%(funcName)s) # PROCESS ID %(process)s >>> THREAD ID %(thread)s\n || %(message)s \n')



def manage_client(connstream, client_socket, addr):
    print("~~ Step 6/6 successful [Server started admitted request in new thread (Client {})] ~~".format(addr))
    logging.debug("~~ Step 6/6 successful [Server started admitted request in new thread (Client %s)] ~~", addr)
    connstream.sendall(b'Server accepted the connection!')

    usr_accepted = False
    while True:
        data = connstream.recv(4096).decode("utf-8")
        print("Client {}: ".format(addr), data)
        logging.debug("Client %s: %s", addr, data)
        if data == 'exit':
            disconnect(connstream, addr)
            break
        elif data == "show status":
            if usr_accepted:
                show_status(connstream)
        elif data == "username":
            usr_accepted = authentication(connstream, addr)
            if not usr_accepted:
                disconnect(connstream, addr)
                break
            continue
        elif data == "count":
            for i in range(1, 10):
                connstream.sendall(str(i).encode("utf-8"))
                time.sleep(3)
        try:
            #connstream.sendall(b'Servertestmessage')
            pass
        except BrokenPipeError as e:
            print(e)
            logging.debug(e)
            logging.exception('Got exception here')
            print("MESSAGE COULD NOT BE SEND!")
            logging.debug("MESSAGE COULD NOT BE SEND!")
            connstream.close()
            break


def authentication(connstream, addr):
    usr_name = connstream.recv(4096).decode("utf-8")
    usr_pwd = connstream.recv(4096).decode("utf-8")
    if usr_name in AUTHENTICATIONS:
        auth_pwd = AUTHENTICATIONS[usr_name]
        if auth_pwd == usr_pwd:
            connstream.send(b'Authentication succeeded!')
            logging.debug("CLIENT AUTHENTICATION FROM {} ACCEPTED".format(addr))
            return True
    connstream.send(b'Authentication failed!')
    logging.debug("CLIENT AUTHENTICATION FROM {} NOT ACCEPTED".format(addr))
    return False



def disconnect(connstream, addr):
    print("+++++ SOCKET CLOSED +++++   [Client {}]".format(addr))
    logging.debug("+++++ SOCKET CLOSED +++++   [Client {}]".format(addr))
    connstream.close()

def show_status(connstream):
    server_location_time = ctime()
    connstream.sendall(server_location_time.encode("utf-8"))
    connstream.sendall("Location: CHINA".encode("utf-8"))
    connstream.sendall("Adress: XYZ".encode("utf-8"))
    connstream.sendall("Last update: Oct-11-2019".encode("utf-8"))
    connstream.sendall("Python Version: 3".encode("utf-8"))


def main():
    try:
        context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
        context.load_cert_chain(certfile="/home/fin/server.crt", keyfile="/home/fin/server.key")
        print("~~ Step 1/6 successful [Loading ssl certification]~~")
        logging.debug("~~ Step 1/6 successful [Loading ssl certification]~~")
    except FileNotFoundError:
        print("CERTIFICATE NOT FOUND!!")
        logging.exception("Certificate could not be loaded. Program is not running anymore. Please restart the program!")
        logging.error("Certificate could not be loaded. Program is not running anymore. Please restart the program!")

    server_socket = socketlib.socket(socketlib.AF_INET, socketlib.SOCK_STREAM)
    with server_socket:
        server_socket.bind((HOST, PORT))
        print("~~ Step 2/6 successful [Socket Binding IP {} on PORT {} as IPv4] ~~".format(HOST, PORT))
        logging.debug("~~ Step 2/6 successful [Socket Binding IP {} on PORT {} as IPv4] ~~".format(HOST, PORT))
        server_socket.listen()
        print("~~ Step 3/6 successful [Server is listening for requests] ~~")
        logging.debug("~~ Step 3/6 successful [Server is listening for requests] ~~")
        try:
            while True:
                    client_socket, addr = server_socket.accept()
                    print("~~ Step 4/6 successful [Server got a request from {}] ~~".format(addr))
                    logging.debug("~~ Step 4/6 successful [Server got a request from %s] ~~", addr)
                    client_socket = context.wrap_socket(client_socket, server_side=True)
                    print("~~ Step 5/6 successful [Request is ssl encrypted now (Client {})] ~~".format(addr))
                    logging.debug("~~ Step 5/6 successful [Request is ssl encrypted now (Client %s)] ~~", addr)

                    Thread(target=manage_client, args=(client_socket, server_socket, addr), daemon=True).start()

        except KeyboardInterrupt as e:
            print(e)                       
            logging.exception(e)




if __name__ == "__main__":
    main()

и клиент:

#::::::::::::::::::::::::::::::::::#
#::::     MULTITHREAD + SSL    ::::#
#:::::::::: [ client.py] ::::::::::#
#::::::::::::::::::::::::::::::::::#
#TODO: logs

import socket, ssl, pprint, sys
from _thread import *
import time
import hashlib

#global msg
#msg = ''

IP = '127.0.0.1'
PORT = 4200




def msg_receive(conn, IP):
    try:
        while True:
            msg = conn.recv(4096).decode("utf-8")
            print("\n[{}]: {}".format(IP, msg))
            time.sleep(0.000001)
            if msg == '':
                print("LOST CONNECTION TO SERVER!")
                print("TRYING TO RECONNECT... (Refresh Browser!)") #TODO:
                conn.close()
                break
    except OSError as e:
        return


def msg_print_send(conn, IP):
    while True:
        message = input("\nNachricht: ")
        conn.sendall(message.encode("utf-8"))
        if message == 'username':
            usr_message = input("\nBN: ")
            conn.sendall(usr_message.encode("utf-8"))
            pwd_message = hashlib.sha512(bytes(input("\nPW: "), "utf-8"))
            p_message = (pwd_message.hexdigest())
            conn.sendall(p_message.encode("utf-8"))

        if message == 'exit':
            print("+++++ SOCKET CLOSED +++++")
            conn.close()
            sys.exit() #TODO: skript beendet sich nicht
            break

        #if message != '':
            #conn.sendall(message.encode("utf-8"))
    #return


def main():
    context = ssl.SSLContext()
    context.verify_mode = ssl.CERT_REQUIRED
    context.check_hostname = True

    try:
        context.load_verify_locations("/home/fin/server.crt")
        print("***CHECK- Certificate loading successful")
    except (FileExistsError, FileNotFoundError) as e:
        print(e)
        print("::::: Program will be closed now! :::::")
        sys.exit()

    try:
        # with socket.create_connection((ip, port)) as s:
        conn = context.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM), server_hostname="127.0.0.1")
        print("***CHECK- Socket only supports ssl connection successful")
        try:
            conn.connect((IP, PORT))
            print("***CHECK- Connection to server successful")
            conn.sendall(b"Thanks for accepting the connection!")
            print("***CHECK- Bytestring sending successful")
        except:
            print("CONNECTION NOT POSSIBLE! IN 10 SECONDS TRYING TO CONNECT AGAIN..")
            time.sleep(10.0)
            return
    except ssl.CertificateError as e:
        # print("Error {}: {}".format(e.args[0], e.args[1]))
        # print("Error {}:".format(e))  #TODO: Darf Ziel-IP bekannt sein? (Fehlerprovokation bei Hackern) SICHERHEITSMANGEL!
        print("Hostname doesn't match.")
        print("::::: Program will be closed now! :::::")
        sys.exit()
    except ConnectionError as e:
        # print("Error {}: {}".format(e.args[0], e.args[1]))
        print(e)
        print("::::: Program will be closed now! :::::")
        sys.exit()

    start_new_thread(msg_receive, (conn, IP))
    start_new_thread(msg_print_send, (conn, IP))


    try:
        while 1:
            #pass
            time.sleep(1)
    except KeyboardInterrupt as e:
        print(e)


if __name__ == "__main__":
    main()


Большое спасибо!

1 Ответ

0 голосов
/ 23 октября 2019

Наконец я узнал: код работает нормально с ssl socket + threading.

Единственная ошибка была в моем server.py: для получения + отправки я использовал только ОДИН поток. Поэтому каждый раз, когда я хочу что-то отправить, я открываю новую ветку. Для получения WHILE необходима 1 тема:] Мой плохой.

В любом случае, спасибо!

...