Я думаю, что @Anonyme2000 ответил на вопрос полностью, и есть все детали, необходимые для решения проблемы. Однако, поскольку это учебное упражнение из книги, другие могут прийти сюда и узнать подробности о том, что происходит в @Anonyme2000. ответы немного короткие, я расширю еще немного.
Струны
В Python, как и во многих других языках, есть так называемые Escape-последовательности, короче говоря, помещающие \ перед чем-то означает, что все, что последует, будет иметь особое значение. Два примера:
Пример 1: разрывы строк (новая строка)
print("Something \nThis is a new line")
Это заставит python интерпретировать n не как букву «n», а как специальный символ, указывающий, что «здесь должна быть новая строка», и все благодаря тому, что \n перед буквой n. \r также является "новой строкой", но в прежние времена это было эквивалентно перемещению переместить головку принтера в начало строки, а не только на одну строку вниз.
Пример 2. Экранирование кавычек в строках
print("I want to print this quote: \" in my string")
В этом примере, поскольку мы используем символ кавычек " для начала и конца нашей строки, добавление его в середину приведет к разрыву строки (надеюсь, вам это понятно) , Чтобы затем продолжить добавление кавычек в середине текста, нам нужно снова добавить символ escape-последовательности \ перед кавычкой, это говорит Python не анализировать кавычку как кавычку, а просто добавьте его в строку.Есть альтернатива этому, а именно:
print('I want to print this quote: " in my string')
И это потому, что вместо этого вся строка начинается и заканчивается ', что позволяет Python точно угадать (разобрать) начало и конец фактической всей строки, что делает его на 100% уверенным, что цитата в этом случай - просто еще один кусок строки. Эти управляющие последовательности описаны здесь с дополнительными примерами.
Байты против строк
Чтобы лучше понять разницу, мы сначала посмотрим, как взаимодействуют Python и терминал, который вы используете. Я предполагаю, что вы запускаете свои скрипты Python из cmd.exe
, powershell.exe
или в Linux что-то вроде xterm
или что-то в этом роде. Основные терминалы, которые есть.
Терминал попытается проанализировать все, что отправлено в его выходной буфер, и представить его вам. Вы можете проверить это, выполнив:
print('\xc3\xa5\xc3\xa4\xc3\xb6') # Most Linux systems
print('\xe5\xe4\xf6') # Most Windows systems
Теоретически один из приведенных выше отпечатков должен был позволить вам просто напечатать кучу байтов, которые терминал каким-то образом знал, как отображать как åäö. Даже ваш браузер только что сделал это за вас (забавное замечание, так они решают и проблему эмодзи, все согласны с тем, что определенные комбинации байтов должны стать ????). Я говорю большинство Windows и Linux, потому что этот результат полностью зависит от того, какой регион/язык вы выбрали при установке операционной системы. Я нахожусь на севере ЕС (Швеция), поэтому мой кодек по умолчанию в Windows — ISO-8859-1
, а на всех моих машинах с Linux у меня UTF-8
. Эти кодеки важны, так как это машинно-человеческий интерфейс для представления текста.
Зная это, все, что вы отправляете в выходной буфер вашего терминала, выполняя print("...")
или sys.stdout.write("...")
, будет интерпретироваться терминалом и отображаться в вашей локали. Если это невозможно, будут возникать ошибки.
Именно здесь Python2 и Python3 начинают становиться двумя разными зверями. И именно поэтому вы здесь сегодня. Проще говоря, Python2
проделал множество автоматических и волшебных «угадываний» над строками, чтобы вы могли отправить строку в сокет, а Python позаботьтесь о кодировке для вас. Python2 анализировал их и преобразовывал всевозможными способами. В Python3
многие автоматические догадки были удалены, потому что это чаще всего сбивало с толку людей. И данные, отправляемые через функции и сокеты, были, по сути, данными Шрёдингера, иногда это были строки, а иногда — байты. Вместо этого теперь вы, разработчик, должны преобразовывать данные и кодировать их... всегда.
Итак, что такое байты против строк?
байты man термины, строка, которая не была закодирована каким-либо образом и, следовательно, может содержать что-либо, связанное с «данными». Это не обязательно должна быть просто строка (a-Z, 0-9, !"#¤% и т. д.), она также может содержать специальные байты, такие как \x00 который представляет собой Нулевой байт/символ. И Python никогда не будет пытаться автоматически анализировать эти данные в Python 3. И при выполнении:
print(b'\xe5\xe4\xf6')
Как и выше, за исключением того, что вы определяете строку как bytes string
в Python3, Python вместо этого отправит представление байтов а не фактические байты в буфер терминала, таким образом, терминал никогда не будет интерпретировать их как фактические байты они.
Пример 1: Кодирование ваших данных
Что подводит нас к этому первому примеру. Так как же преобразовать ваш bytes
, содержащий print(b'\xe5\xe4\xf6')
, в представленные символы в вашем терминале, ну, преобразовав его в строки с определенной кодировкой. В приведенном выше примере три символа \xe5\xe4\xf6
оказались кодировщиком ISO-8859-1
в процессе создания. Я знаю это, потому что в настоящее время я работаю в Windows, и если вы запустите команду chcp
в своем терминале, вы получите какую кодовую страницу/кодер вы используете.
Там я могу сделать:
print(b'\xe5\xe4\xf6'.decode('ISO-8859-1')
И это преобразует объекты bytes
в объект string
(с кодировкой).
Проблема здесь заключается в том, что если вы отправите эти string
на мою машину с Linux, он не будет иметь ни малейшего представления о том, что происходит. Потому что, если вы попробуете:
print(b'\x86\x84\x94'.decode('UTF-8'))
Вы получите сообщение об ошибке, подобное этому:
>>> print(b'\x86\x84\x94'.decode('UTF-8'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x86 in position 0: invalid start byte
Это потому, что в стране UTF-8
байта \x86
не существует. Так что у него нет способа узнать, что с ним делать. И поскольку кодировщик по умолчанию на моей машине с Linux - UTF-8
, ваши данные Windows - мусор для моей машины.
Что приводит нас к ..
Розетки
В Python3 и большинстве физических областей компьютера кодировки и строки не приветствуются, поскольку на самом деле они не являются чем-то особенным. Вместо этого машины взаимодействуют битами, в короткие, 1 и 0. 8 из них становятся byte
, и именно здесь в игру вступает bytes
Python. При отправке чего-либо с машины на машину (или из приложения в приложение) нам придется преобразовать любое текстовое представление в последовательность bytes
, чтобы машины могли общаться друг с другом. Без кодировок, без разбора вещей. Просто - возьмите данные.
Мы делаем это тремя способами, и они:
print('åäö'.encode('UTF-8'))
print(bytes('åäö', 'UTF-8'))
print(b'åäö')
Последний вариант не сработает, но я намеренно оставлю его таким, чтобы показать разницу между сообщением Python "эй, эта странная штука, преобразуй ее в байтовый объект".
Все эти параметры вернут bytes
представление åäö
с использованием кодировщика * (кроме последнего, он будет кодировать только с использованием ASCII синтаксический анализатор, который в лучшем случае ограничен).
В случае UTF-8
вам будет возвращено что-то вроде:
b'\xc3\xa5\xc3\xa4\xc3\xb6'
И это, это то, что вы можете отправить через сокет. Потому что это всего лишь последовательность байтов, которую терминалы, машины и приложения не будут касаться или обрабатывать каким-либо иным образом, кроме как последовательность единиц и нулей * ("11000011 10100101 11000011 10100100 11000011 10110110", если быть точным)
Вместе с некоторой сетевой логикой это то, что будет отправлено на ваш сокет. И вот как машины общаются.
Это обзор того, что происходит. «Человек» — это терминал, также известный как машинно-человеко-интерфейс, куда вы вводите свой åäö, а терминал кодирует/анализирует его как определенную кодировку. Ваше приложение должно творить чудеса, чтобы преобразовать его во что-то, с чем может работать сокет/физический мир.
person
Torxed
schedule
10.06.2020
client.send
слишком много символов обратной косой черты. Вы избежали закрытия"
. Попробуйте:client.send("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")
- person larsks   schedule 08.06.2020bytes
передачи объектов в сокет и из него. так чтоsocket.send("GET ...)
на самом деле должно быть, например,socket.send(bytes("GET ...", 'UTF-8'))
. - person Torxed   schedule 08.06.2020