LINUX.ORG.RU

Почему много write обрабатываются как один?


0

2

Я пишу сервер. Использую epoll. Когда посылаю много пакетов на сервер через send или write - они аккумулируются в один. Но стоит добавить sleep на 1/100 секунды например - всё ок.

Что это такое и как с этим бороться?

Вот код тестера на ruby.

require 'socket'

login = 'optimus'.ljust(32, [0].pack('c'));
password = 'prime'.ljust(32, [0].pack('c'));

command = [0x70].pack('s') + [0x1].pack('c') + [0x0].pack('c') + [login.length + password.length].pack('L') + login + password

puts "Command length: #{command.length}"

sock = TCPSocket.open('localhost', 7851)

5.times {
	sock.write command
}

sock.close

Я думаю, что в буфер всё собирается, и когда буфер полон всё отправляется на сервер. Ты хочешь побайтово что ли операции ввода/вывода совершать? Это дорого стоит

Zorn
()

лол

Ruby программисты такие программисты.

anonymous
()
Ответ на: комментарий от ur

При sock.close всё отсылаться должно.

Да, вдруг я тебя не понимаю. Ты имеешь в виду, что инфа шлется не сразу, а через какое-то время/ кол-во операций ввода/вывода?

Zorn
()
Ответ на: комментарий от ur

зря боишься. пакеты придут в порядке постановки в очередь отправки.

qbe
()

IP-пакеты могут по дороге произвольным образом разделяться на несколько или же склеиваться из нескольких. Они все дойдут до нужного хоста, он их уже соберёт в нужном порядке, если они поменялись местами, и отдаст одним или несколькими пакетами программе на удалённом хосте. Поэтому протокол надо проектировать так, чтобы он не зависел от уровня пакетов. Если это действительно надо, запили свои пакеты. Например, посылаешь магическое слово, длину пакета, контрольную сумму, а дальше пакет. Удалённый хост принимает магическое слово, длину, КС, ждёт, пока по кускам придёт ВЕСЬ пакет (есть длина), проверяет контрольную сумму и передаёт данные пакета нужной функции, выполняющей над ним действия.

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

IP-пакеты могут по дороге произвольным образом разделяться на несколько или же склеиваться из нескольких. Они все дойдут до нужного хоста, он их уже соберёт в нужном порядке,

sock = TCPSocket.open('localhost', 7851)

не пугай топикстартера, у него же TCP пакеты, которые доставляются в сокет в том же порядке, в котором были отправлены

(естественно, на IP уровне они могли перед этим быть перемешаны)

qbe
()
Ответ на: комментарий от qbe

Большое спасибо. Понимаю теперь хоть почему.

Я видел в протоколе memcached использование «мусора» - uint8_t bytes[24] - например. Т.к. там пакеты маленькие - я понимаю они так решили эту проблему? Значит как я понял нужно увеличить размер пакета до <40 байтов?

ur
() автор топика

TCPSocket

посылаю много пакетов

Эталонное незнакомство с матчастью обнаружено. За вами уже выехали. Оставайтесь на месте и не совершайте резких движений. Благодарим за сотрудничество.

З.Ы. Ты хотя бы знаешь, что такое TCP?

geekless ★★
()
Ответ на: комментарий от ur

Я видел в протоколе memcached использование «мусора» - uint8_t bytes[24] - например. Т.к. там пакеты маленькие - я понимаю они так решили эту проблему? Значит как я понял нужно увеличить размер пакета до <40 байтов?

Зачем вам это? Эффективней же собирать пакеты в один, меньше трафика уходит на заголовки. А в точке назначения вам их всёравно потоком байт отдавать будут.

Norgat ★★★★★
()
Ответ на: комментарий от ur

Нет, неправильно. Есть опция сокета TCP_NODELAY, которая заставляет сокет отправлять данные немедленно, невзирая на оверхед (например, при отправке одного байта у тебя будет ещё байт 40 на заголовки TCP, IP, ETHERNET, а может и более, если используется, к примеру PPTP)

Но использовать TCP_NODELAY есть смысл только на операциях реального времени, когда задержка на накопление данных критична.

А протокол обмена с сервером должен быть спроектирован так, чтобы было неважно, придёт ли одна команда в пакете, несколько команд в пакете, или даже если команда дойдёт до сервера кусочками по 1 байту (естественно, последовательно)

например, полная команда заканчивается кодом 0x0A (LF), как в терминале, либо команда завёрнута в XML, как в XMPP, либо команда начинается с заголовка, содержащего значение длинны команды

qbe
()
Ответ на: комментарий от qbe

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


typedef struct ProtocolRequestHeader {
	uint16_t magic;
	uint8_t cmd;
	uint8_t reserved;
	uint32_t bodylen;
} ProtocolRequestHeader;

typedef struct ProtocolBinaryRequestAuth {
	struct {
		ProtocolRequestHeader header;
		struct {
			uint8_t login[32];
			uint8_t password[32];
		} body;
	} message;
} ProtocolBinaryRequestAuth;

в bodylen храню количество данных, и жду пока все не придут(собираю кусочками).

ur
() автор топика
Ответ на: комментарий от geekless

сегодня тяпница, я добрый и многословный :)

qbe
()
Ответ на: комментарий от sn1ln

Имеется ввиду TCP_CORK?

TCP_CORK (since Linux 2.2) If set, don't send out partial frames. All queued partial frames are sent when the option is cleared again. This is useful for prepending headers before calling sendfile(2), or for throughput optimization. As currently implemented, there is a 200 millisecond ceiling on the time for which output is corked by TCP_CORK. If this ceiling is reached, then queued data is automatically transmitted. This option can be combined with TCP_NODELAY only since Linux 2.5.71. This option should not be used in code intended to be portable.

Похоже то что нужно. Сделаю эксперимент.

ur
() автор топика
Ответ на: комментарий от ur

они сделали так для выравнивания.

у memcached текстовой протокол. То что ты говоришь, похоже, просто сделано для бинарной совместимости либ - резервируют кусок. Или ещё для какой хрени. А выравнивает компилер всё сам.

true_admin ★★★★★
()
Ответ на: комментарий от sn1ln

TCP_PUSH

и как его выставить? Уж не setsockopt(TCP_NODELAY) ли потребуется?

true_admin ★★★★★
()
Ответ на: комментарий от sn1ln

TCP_PUSH

Просвети, как юзать? А то в протоколе вроде заложено, а в socket API не отражено.

pathfinder ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.