#ruby #sockets
#ruby #сокеты
Вопрос:
Сокеты TCP — это потоки, а не сообщения, поэтому send()
функция сокетов berkeley в некоторых системах может отправлять меньше данных, чем требуется. Поскольку сокет Ruby является очень тонкой оболочкой для сокетов berkeley, AFAIK Socket#send
будет вести себя точно так же, как сокеты berkeley send()
. Итак, каков правильный способ отправки полного сообщения через TCP-сокеты Ruby? В python для этого вызывается специальная функция sendall()
. Но в Ruby мне нужно вручную писать такой код:
while (sent = sock.send( data, 0 ) < data.length do
data = data[ sent..-1 ]
end
Ответ №1:
Чтобы расширить то, что говорит danielnegri, IO.write
заканчивается вызовом io_binwrite
io.c
Соответствующий бит исходного кода ruby приведен ниже ( n
и len
изначально устанавливается на длину ваших данных и offset
на 0)
retry:
arg.offset = offset;
arg.length = n;
if (fptr->write_lock) {
r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)amp;arg);
}
else {
long l = io_writable_length(fptr, n);
r = rb_write_internal(fptr->fd, ptr offset, l);
}
if (r == n) return len;
if (0 <= r) {
offset = r;
n -= r;
errno = EAGAIN;
}
if (rb_io_wait_writable(fptr->fd)) {
rb_io_check_closed(fptr);
if (offset < RSTRING_LEN(str))
goto retry;
}
return -1L;
Как вы можете видеть, пока он не записал все данные, он будет продолжать делать goto retry
и пытаться снова. rb_io_wait_writable
в основном проверяет, что значение errno
таково, что следует повторить попытку (в отличие от чего-то более фатального), а затем вызывает select
, чтобы избежать ожидания занятости.
Комментарии:
1. Большое спасибо, именно то, что мне нужно.
Ответ №2:
Недавно я использовал метод ‘write’:
require "socket"
server = TCPServer.new('localhost', 20000)
loop do
Thread.start(server.accept) do |s|
print(s, " is acceptedn")
server.write(Time.now)
print(server, " is gonen")
server.close
end
end
Попробуйте:
require 'socket'
sock = Socket.open(Socket::PF_INET,Socket::SOCK_STREAM,Socket::IPPROTO_TCP)
@data = "anyThing"
@addr = pack_sockaddr_in(port, host)
sock.connect(@addr) #make the connection
sock.send(@data, 0)
Вы также можете попробовать использовать класс TCPSocket . Я не использовал ни один из этих кодов Ruby, поэтому я не привык к этой конкретной библиотеке; пожалуйста, дайте мне знать, если я все понял неправильно.
require 'socket'
sock = TCPSocket.new(host, port)
@data = "anyThing"
sock.send(@data, 0)
Комментарии:
1. Есть ли какие-либо доказательства того, что
write
обрабатывает частичную отправку?