Guest User

Untitled

a guest
Jul 1st, 2020
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.81 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. import socket
  3. import threading
  4. import queue
  5. import time
  6. import codecs
  7. import sys
  8. # Определяем константу содержащую имя ОС
  9. # для учёта особенностей данной операционной системы
  10. import platform
  11. OS_NAME = platform.system()
  12.  
  13.  
  14.  
  15. # Константы
  16. HOST = 'Ваш ip'
  17. PORT = 1080
  18.  
  19. # Единственная глобальная переменная
  20. # доступная всем потокам
  21. run = True
  22.  
  23.  
  24.  
  25. def shutdown_socket(s):
  26. # В Linux'ах просто закрыть заблокированный сокет будет мало,
  27. # он так и не выйдет из состояния блокировки. Нужно передать
  28. # ему команду на завершение. Но в Windows наоборот, команда
  29. # на завершение вызовет зависание, если сокет был заблокирован
  30. # вызовом accept(), а простое закрытие сработает.
  31. if OS_NAME == 'Linux':
  32. s.shutdown(socket.SHUT_RDWR)
  33. s.close()
  34.  
  35. def reciver(client, q):
  36. while run:
  37. try:
  38. # Здесь поток блокируется до тех пор
  39. # пока не будут считаны все имеющиеся
  40. # в сокете данные
  41. data = client.recv(1024)
  42. message = client.recv(1024)
  43.  
  44. if data: # Если есть данные
  45. # Отправляем в очередь сообщений кортеж
  46. # содержащий сокет отправителя
  47. # и принятые данные
  48. q.put((client, data))
  49. print('{} отправил: {}'.format(client.getpeername(), data.decode()))
  50. except:
  51. break # В случае ошибки выходим из цикла
  52. client.close() # И закрываем клиентский сокет
  53.  
  54.  
  55. def sender(q, connections):
  56. while run:
  57. closed_sockets = set()
  58. try:
  59. # Получаем из очереди сообщений
  60. # сокет отправителя и принятые данные
  61. sender, message = q.get(timeout=1)
  62. except queue.Empty:
  63. pass # Игнорируем отсутствие сообщений в очереди
  64. else: # Если же сообщения есть
  65. for s in set(connections): # Обходим все сокеты
  66. if s != sender: # Кроме сокета отправителя
  67. try:
  68. s.send(message) # И отправляем им принятое сообщение
  69. sys.stderr1.write(message)
  70.  
  71. except:
  72. closed_sockets.add(s)
  73. if closed_sockets:
  74. with threading.Lock():
  75. connections -= closed_sockets
  76. print("Подключено:", len(connections))
  77. q.task_done() # Сообщаем, что сообщение обработано
  78.  
  79.  
  80. def accepter(server, connections, q):
  81. while run:
  82. try:
  83. # Здесь поток блокируется до тех пор, пока кто-то не подключится к серверу
  84. client, addr = server.accept()
  85. except OSError as e:
  86. # Если отловлена не ожидаемая ошибка закрытия серверного сокета, а какая-то другая
  87. if (OS_NAME == 'Windows' and e.errno != 10038) or (OS_NAME == 'Linux' and e.errno != 22):
  88. raise # то возбуждаем её повторно
  89. else: # Если кто-то подключился и создан новый клиентский сокет
  90. # Устанавливаем ему таймаут, чтобы считать его сбойным,
  91. # если в этот сокет не будут ничего писать более 5 минут
  92. client.settimeout(60 * 5)
  93. with threading.Lock():
  94. connections.add(client)
  95. # Запускаем новый поток, выполняющий функцию receiver
  96. # для только что полученного сокета
  97. threading.Thread(target=reciver, args=(client, q)).start()
  98. print("Подключено:", len(connections))
  99.  
  100.  
  101. if __name__ == '__main__':
  102. print('Запуск...')
  103.  
  104. # Очередь сообщений, через которую будут общаться потоки
  105. q = queue.Queue()
  106. # Множество соединений
  107. connections = set()
  108.  
  109. server = socket.socket()
  110. server.bind((HOST, PORT))
  111. server.listen()
  112.  
  113. print(u'Сервер запущен на {}\n'.format(server.getsockname()))
  114.  
  115. # Поток получающий сообщения из очереди
  116. # и отправляющий их всем сокетам в множестве connections
  117. threading.Thread(target=sender, args=(q, connections)).start()
  118. # Поток принимающий новые соединения
  119. threading.Thread(target=accepter, args=(server, connections, q)).start()
  120.  
  121. while True:
  122. command = input()
  123. if command == 'exit': # Если в консоли введена команда exit
  124. run = False # отменяем выполнение циклов во всех потоках
  125. break # и выходим из этого цикла
  126. for s in connections:
  127. shutdown_socket(s)
  128. shutdown_socket(server)
Add Comment
Please, Sign In to add comment