Нашёл хороший туториал (PDF) на английском про сетевое программирование в Python — чётко изложена сама теория, кое-чего я и сам не знал, и даны хорошие базовые примеры на Python.
На сайте автора есть и другие неплохие туториалы про Python.
14 мая 2010 г.
5 мая 2010 г.
UDP-траспорт
В проекте, над которым я работаю, понадобилось использовать асинхронный UDP-траспорт. Как выяснилось, есть в этой задаче несколько подводных камней — о них и пойдёт речь.
Хотелось что-то максимально простое с помощью встроенных в Python средств.
Первый вариант — класс SocketServer.UDPServer. Минус его в том, что он использует блокирующие сокеты; для обхода этого в том же пакете есть и неблокирующие версии, реализованные с помощью тредов или даже отдельных процессов на каждого клиента. Но это не совсем асинхронность.
Второй способ — пакет asyncore, который как раз для асинхронных сообщений и предназначен. Правда, только для TCP. Создать нужный класс несложно, но есть несколько тонкостей:
Вот, собственно, и всё, все хитрости прокомментированы в коде. Естественно, нам не требуется
Хотелось что-то максимально простое с помощью встроенных в Python средств.
Первый вариант — класс SocketServer.UDPServer. Минус его в том, что он использует блокирующие сокеты; для обхода этого в том же пакете есть и неблокирующие версии, реализованные с помощью тредов или даже отдельных процессов на каждого клиента. Но это не совсем асинхронность.
Второй способ — пакет asyncore, который как раз для асинхронных сообщений и предназначен. Правда, только для TCP. Создать нужный класс несложно, но есть несколько тонкостей:
class UdpTransport(asyncore.dispatcher, object):
def __init__(self, addr=None):
super(UdpTransport, self).__init__()
self.ignore_log_types = set() # Для вывода дополнительных ошибок в asyncore, подсмотрел в исходниках asyncore :)
self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
# Размер этого буфера очень важен
# Если входящий пакет будет больше него, остаток отбрасывается
self.ReadBufferSize = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
if addr:
self.bind(addr) # Единственное отличие серверного сокета в использовании bind()
def handle_close(self):
self.close()
def writable(self):
return False
def handle_read(self):
try:
data, addr = self.recvfrom(self.ReadBufferSize)
except socket.error: # Исключение возникает при чтении данных из сокета: когда они заканчиваются, следующая попытка вылетает
pass
# обработка данных
def send(self, msg, toaddr):
self.socket.sendto(msg, toaddr)
handle_connect = handle_read # Нарыл где-то на просторах инета
# Без этого asyncore не работает с UDP, первую порцию данных он интерпретирует как инициализацию подключения
Наследуемся и от object для использования super и отладки с помощью метакласса.Вот, собственно, и всё, все хитрости прокомментированы в коде. Естественно, нам не требуется
connect() для серверных сокетов, а вместо socket.send/recv нужно использовать методы sendto/recvfrom. Сперва я путался, в каких случаях что нужно применять — документация лаконична — но нашёл хороший источник с примерами, это наш родной `man`. ;) Например, `man bind` (или `man 2 bind`, если быть точным) показывает документацию С-шного сетевого API, обёрткой вокруг которого socket, собственно, и является. Если на вашем *nix такой странички нет, нужно установить пакет manpages-dev (в Debian и Ubuntu, по крайней мере).
28 апреля 2010 г.
Мощь Python
Я не так давно читал про метаклассы в Питоне, и тут представился случай их использовать.
Задача: нужно отладить код сетевого приложения, дебаггером по нему не пройдёшь — при пошаговой отладке состояние сокетов теряется. Я решил печатать имя и аргументы каждого вызванного метода сетевых классов. Вариант со вставкой print в каждый метод — это явно не наш метод. :)
Получился вот такой метакласс:
Класс, который будет использовать этот метакласс, должен наследоваться от object. В моём случае выглядит примерно так:
Сам dispatcher — это old-style class, поэтому я добавляю ещё одного родителя, но если поместить его первым, лезут баги.
Прекрасные материалы о метаклассах, new-style классах и прочей магии Питона есть на Хабре.
Про обёртки, сиречь декораторы, можно почитать в блоге Романа Ворушина.
Задача: нужно отладить код сетевого приложения, дебаггером по нему не пройдёшь — при пошаговой отладке состояние сокетов теряется. Я решил печатать имя и аргументы каждого вызванного метода сетевых классов. Вариант со вставкой print в каждый метод — это явно не наш метод. :)
Получился вот такой метакласс:
class DebugMetaclass(type):
'''Вывод вызова каждого метода объекта с параметрами, удобно при отладке
сетевых приложений. ;)'''
def __new__(cls, name, bases, attrs):
cls.last_signature = None
for elem in attrs:
if inspect.isfunction(attrs[elem]):
attrs[elem] = DebugMetaclass.decorator(attrs[elem])
return super(DebugMetaclass, cls).__new__(cls, name, bases, attrs)
@classmethod
def decorator(cls, func):
'''Возвращает обёрнутую функцию.'''
@wraps(func)
def wrapper(*args, **kwargs):
signature = '%s.%s(%s, %s)' % (args[0].__class__.__name__,
func.__name__, ', '.join([str(a) for a in args]),
kwargs)
if cls.last_signature != signature: # Добавлено для подавления повторяющихся сообщений
print signature
cls.last_signature = signature
return func(*args, **kwargs)
return wrapper
Класс, который будет использовать этот метакласс, должен наследоваться от object. В моём случае выглядит примерно так:
class UdpTransport(asyncore.dispatcher, object):
__metaclass__ = DebugMetaclassСам dispatcher — это old-style class, поэтому я добавляю ещё одного родителя, но если поместить его первым, лезут баги.
Прекрасные материалы о метаклассах, new-style классах и прочей магии Питона есть на Хабре.
Про обёртки, сиречь декораторы, можно почитать в блоге Романа Ворушина.
23 апреля 2010 г.
В поисках утраченных исходников
Сегодня я работал над модульными тестами для своего Python-проекта. Для простоты файлы тестов называю так же, как и файлы тестируемых модулей. Я решил перенести тесты в другой каталог и мимодумно скопировал их в каталог модулей. Исходники модулей, конечно, затёрлись.
"А-а-а-а!!!" — подумал я. К счастью, остались оригинальные *.pyc-файлы — скомпилированный байт-код Python, который, по идее, можно превратить обратно в исходник.
Быстрый поиск выдал замечательный пост на не менее замечательном StackOverflow. Бесплатная утилита UnPyc помогла почти полностью восстановить один из файлов, но споткнулась на другом, с list comprehensions. Тогда я решил воспользоваться онлайн-сервисом DePython, но у него два ограничения:
К счастью, модулей было всего два :), осталась последняя закавыка — текст на русском раскодировался в виде \xx-последовательностей. Тогда я обернул текст исходников в такой код:
Мораль сего такова: будьте внимательны, чаще коммитьте и не отчаивайтесь.
"А-а-а-а!!!" — подумал я. К счастью, остались оригинальные *.pyc-файлы — скомпилированный байт-код Python, который, по идее, можно превратить обратно в исходник.
Быстрый поиск выдал замечательный пост на не менее замечательном StackOverflow. Бесплатная утилита UnPyc помогла почти полностью восстановить один из файлов, но споткнулась на другом, с list comprehensions. Тогда я решил воспользоваться онлайн-сервисом DePython, но у него два ограничения:
- размер файла должен быть меньше 5 КБ;
- версия Python <= 2.5.
К счастью, модулей было всего два :), осталась последняя закавыка — текст на русском раскодировался в виде \xx-последовательностей. Тогда я обернул текст исходников в такой код:
print """ <здесь перекодированный код> """При запуске скрипта в консоли с локалью UTF-8 вывелись строчки с чистым русским текстом. Ура!
Мораль сего такова: будьте внимательны, чаще коммитьте и не отчаивайтесь.
4 апреля 2010 г.
Ретуширование картинок
Недавно наткнулся на видео с показом тестовой фишки в PhotoShop — Content-Aware Fill (заливка, зависимая от содержимого картинки):
Open source ужедва года восемь лет (спасибо, prokoudine!) как имеет в своём распоряжении такой же плагин для Gimp. :)
Ну разве это не красота?
Open source уже
![]() | ![]() |
| До | После (убрал собачку и дома) |
Ну разве это не красота?
5 февраля 2010 г.
Delete your account
С ростом популярности соцсетей появляются и такие сервисы, как Delete Your Account. :)
4 февраля 2010 г.
PHP наносит ответный удар
Facebook вчера обнародовал проект HipHop для PHP — трансформатор исходного кода из PHP в C++. Благодаря ему они достигли 50% прироста в скорости.
P.S. Наконец что-то интересное происходит и в лагере PHP. :)
P.S. Наконец что-то интересное происходит и в лагере PHP. :)
Подписаться на:
Сообщения (Atom)

