Serwer na Socketach, po błędzie nie chce się ponownie uruchomić

0

Mam kod pythona i PHP. W Pythonie klient i serwer i plik php, który z nich korzysta.

#!/usr/bin/python3

# KLIENT  cli.py

import socket
import sys
import os
import time

HOST = ''       # The remote host
PORT = 50007    # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while 1:
    try:
        s.connect((HOST, PORT))
        break
    except Exception as e:
        os.fork()
        os.system("nohup python3 ./serv.py")
        time.sleep(1)
s.send(str(sys.argv[1]).encode())
data = s.recv(1024).decode()
s.close()
print(data, end='')
#!/usr/bin/python3

# SERWER serv.py

import sys
import socket

HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
while 1:
    conn, addr = s.accept()
    data = conn.recv(1024).decode()
    if not data: break
    try:
        conn.send(data + " moje dodatki").encode())  # zamiast stringa jest moja funkcja, która czasem nawala
    except Exception as e:
        conn.send(str(e).replace("\n", " ").encode())
    conn.close()
<?php
        $command = './cli.py ' . '"blah"';
        $output = shell_exec($command);
?>
<span><?php echo $output; ?></span>

Problem polega na tym, że plik php powinien uruchamiać plik klienta, napisanego w pythonie, i to robi. Klient uruchamia serwer, jeżeli ten będzie nieaktywny. Jednak czasem, jak wystąpi jakiś błąd i serwer się wywali, to nie chce się dalej włączyć, bo twierdzi, że na tym porcie, którego używa, jest już coś uruchomione. Tak jakby serwer się nie do końca wyłączał. Nie wiem czym to jest spowodowane, używam Linux Mint 19.3 ale nie znam się na linuxsie. Proszę o pomoc. Dziękuję.

M.

3

Na tym ze jak się wywala wyjątek to powinieneś go złapać i ładnie zamknąć port zeby nie wisiał.

0

Dzięki za info. :)

0

A czy można jakoś przechwycić sytuację, w której ktoś zamyka proces w konsoli wciskając CTRL + Z (Linux)? Da się to obsłużyć w kodzie?

Dzięki
M.

PS. Dodałem ten socketopt ale dostaję dalej taki err:

Traceback (most recent call last):
  File "./serv.py", line 11, in <module>
    s.bind((HOST, PORT))
OSError: [Errno 98] Address already in use
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 154, in apport_excepthook
    os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o640), 'wb') as f:
FileNotFoundError: [Errno 2] No such file or directory: '/var/crash/_var_www_html_strona_serv.py.1000.crash'

Original exception was:
Traceback (most recent call last):
  File "./serv.py", line 11, in <module>
    s.bind((HOST, PORT))
OSError: [Errno 98] Address already in use
0

Załączę cały mój plik serv.py

#!/usr/bin/python3

import sys
import socket

HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
while 1:
    conn, addr = s.accept()
    data = conn.recv(1024).decode()
    if not data:
        conn.close()
        break
    try:
        conn.send("MOJ CONTENT".encode())
    except Exception as e:
        conn.send(str(e).replace("\n", " ").encode())
    conn.close()

Działa tylko 1 raz, w sensie, 1 raz mogę go uruchomić. Po CTRL+Z ponowne uruchomienie zwraca ERROR jak 2 posty wyżej

0

https://realpython.com/python-sockets/ - jak dla mnie to brakuje jakiegoś socket.close

0

No ale jest przecież:

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

PS.

@szatkus No dobra. Wyszukałem i mam proces:

$ lsof | grep serv.py
(...)
serv.py    8236                michal    3u     IPv4              54804       0t0        TCP *:50007 (LISTEN)

Było więcej tych plików na liście. Jak odfiltrować właśnie ten który nasłuchuje?

PS 2.

Odfiltrowałem wynik poleceniem:

lsof | grep serv.py | grep IPv4 | grep LISTEN

Tylko jak teraz odfiltrować numer PID?

1

@mpaw: coś mi się wydaje, że setsockopt() powinien dostać zamiast "1"-ki dwa parametry: wskaźnik na wartość "1" i wielkość bufora przechowującego tę wartość - ale zaznaczam, że tak jest napisane w "man setsockopt", a jak to jest w pythonie to nie wiem. Możesz w każdym razie sprawdzić to i upewnić się czy na pewno tam ma być po prostu "1".

A co do odfiltrowania PID-a to zobacz sobie manuale do awk-a i sed-a. A konkretniej: dodaj sobie np. coś takiego:
| awk '{print $2}'

1 użytkowników online, w tym zalogowanych: 0, gości: 1