Почему сокет отключается?

#python #sockets #python-3.8

#python #сокеты #python-3.8

Вопрос:

Я пытаюсь создать сервер чата между 2 машинами, но есть проблема с подключением. Хотя он изначально подключается, когда дело доходит до отправки каких-либо фактических данных, сокет отключается.

Серверный код

 import socket
import sys
import time
messages = []

x= socket.socket()
h_name = socket.gethostname()
print('Server will start on host address:', h_name)
port = 8000

bind = False
while bind == False:
   try:
      x.bind((h_name, port))
      bind = True
      print('This server is running on port', port)
   except(OSError): #if the port connection doesn't work
      if port == 65535:
         print('Please restart the machine and relaunch this program')
      else:
         port = port   1 #increment the port by 1 and try again
         print('Trying Port '   str(port)   '...')

print( "Server done binding to host and port successfully")
print("Server is waiting for incoming connections")
x.listen(1)
connection,address= x.accept()
print(address, "has connected to the server and is now online...")

while 1:
   display_mess= input(str(">>"))
   if display_mess == 'QUIT': #if the user wants to quit
      confirmation = input('Are you sure you would like to quit (Y/N)? ')
      confirmation = confirmation.upper()
      if confirmation == 'Y':
         print('Press enter to quit...')
         input()
         exit()
   else:
   display_mess=display_mess.encode()
   connection.send(display_mess)
   print("Message has been sent...")
   in_message=connection.recv(1024)
   in_message=in_message.decode()
   print("Client:", in_message)
  

Приведенный выше код должен настроить сервер и ожидать подключения от клиента, а затем они должны иметь возможность обмениваться данными, хотя и по одному сообщению за раз. Сначала сервер должен отправить сообщение, а затем клиент.

Клиентский код

 import socket
import sys
import time
global port
port = 8000


def getHostName():
   global h_name
   h_name= input(str("Enter the hostname of the server: "))

def portConnect(h_name,port):
   x = socket.socket()
   connected = False
   while connected == False:
      x = socket.socket()
      try:
         x.connect((h_name,port))
         print("Connected to chat server")
         connected = True
      except(ConnectionRefusedError):
         print('Port', port, 'is incorrect')
         print('Trying port '   str(port 1)   '...')
         port = int(port 1)
         portConnect(h_name,port)

def while1():
   x = socket.socket()
   while 1:
      x = socket.socket()
      try:
         incoming_message=x.recv(1024)
         incoming_message=incoming_message.decode()
         print(" Server :", incoming_message)
         message= input(str(">>"))
         if message == 'QUIT':
            confirmation = input('Are you sure you would like to quit (Y/N)? ')
            confirmation = confirmation.upper()
            if confirmation == 'Y':
               print('Press enter to quit...')
               input()
               exit()
            else:
               message =message.encode()
               x.send(message)
               print(" message has been sent...")
         else:
            message =message.encode()
            x.send(message)
            print(" message has been sent...")

      except(OSError):
         print('Please check the server machine is running')
         cont = input('Would you like to quit the program or continue (Q/C): ')
         if cont.isnum() != True and len(cont) > 0:
            cont = cont.upper()
            if cont == 'C':
               getHostName()
            else:
               print('Press enter to exit')
               input()
               exit()

getHostName()
portConnect(h_name, port)
while1()
  

Приведенный выше код должен создать клиентский компьютер и выполнить поиск сервера на заранее определенном порту и локальной сети и дождаться соединения с сервером, а затем они должны иметь возможность обмениваться данными, хотя и по одному сообщению за раз. Сначала сервер должен отправить сообщение, а затем клиент.

Вывод на консоль (на компьютере клиента ‘)

 Enter the hostname of the server: *name*
Connected to chat server
Traceback (most recent call last):
  File "******.py", line 71, in <module>
    while1()
  File "******.py", line 38, in while1
    incoming_message=x.recv(1024)
OSError: [Errno 57] Socket is not connected
  

В выводе консоли говорится, что они сначала подключаются, поскольку он отображает Connected to chat server сообщение, но затем они отключаются, поскольку сервер не может отправить какое-либо сообщение.

Если сервер пытается отправить сообщение после того, как сокет был отключен, вывод консоли:

 Traceback (most recent call last):
  File "******.py", line 43, in <module>
      in_message=connection.recv(1024)
  ConnectionResetError: [Errno 54] Connection reset by peer
  

Я полагаю, однако, что эта проблема решится сама собой после того, как проблема с сокетом будет решена.

Комментарии:

1. Вы должны попытаться создать минимальный пример, в котором все еще присутствует проблема, с которой вы сталкиваетесь. Я подозреваю, что проблема в том, что вы воссоздаете сокет в каждой функции вместо того, чтобы передавать подключенный сокет.

Ответ №1:

Большой намек на то, что не так, — это посмотреть, сколько раз вы вызываете socket.socket в клиентском коде. Я вижу четыре разных места, где вы создаете новый сокет: дважды в while1 и дважды в portConnect . Это, конечно, не то, что вы хотите. Ваш код не работает, потому что вы подключаете сокет, созданный в portConnect , затем этот объект сокета выходит из области видимости при завершении функции. x In portConnect — это не то же самое, что x in while1 .

Я бы передал x в portConnect вместо использования вновь созданного сокета:

 def portConnect(h_name, port, x):
    # Don't create a new socket here
    connected = False
    while connected == False:
        # Also don't create a new socket here
    . . .
  

Затем переместите вызов в portConnect куда-нибудь, где x находится область видимости, и вызовите его как:

 portConnect(h_name, port, x)
  

Вы также, вероятно, хотите избавиться от x = socket.socket() внутренней части while 1: цикла.

Вы также можете создать его x в portConnect , а затем return из функции. Вы можете обнаружить, что это имеет больше смысла.


Несколько побочных вещей:

  • while1 это очень плохое название для функции. Название должно описывать, что делает функция, а не подробности о ее реализации.

  • while 1 более понятно, как while True .

  • Такие условия, как while connected == False: , более удобочитаемы и идиоматичны, как while not connected: . Сравнение с True и False напрямую никогда не требуется.

Комментарии:

1. Теперь отправляется сообщение, но при попытке нового питания при запуске это происходит: Traceback (most recent call last): File "/***", line 20, in portConnect x.connect((h_name,port)) ConnectionRefusedError: [Errno 61] Connection refused During handling of the above exception, another exception occurred: Traceback (most recent call last): ***", line 68, in <module> portConnect(h_name, port,x) ***.py", line 27, in portConnect portConnect(h_name,port,x) ***", line 20, in portConnect x.connect((h_name,port)) OSError: [Errno 22] Invalid argument

2. @user14303139 Дважды проверьте, что такое h_name и port . Что h_name вы используете?

3. h_name не изменяется на протяжении всего этого процесса, даже при повторном входе в h_name отображается та же ошибка. Типы переменных точно такие же, как и в первый раз

4. @user14303139 В чем port заключается сбой?

5. Когда сервер запускается на порту 8001 (например), клиент увидит, что h_name открыто, но не на этом порту, поэтому код увеличивает номер порта до 8001 (с исходного значения 8000, установленного в начале клиентского кода), это единственный аргумент, который изменяется. Даже если эта функция изменяется с рекурсивной только на цикл while, возникает та же проблема