2011-10-26 13 views
3

TCPソケットはメッセージではなくストリームなので、一部のシステムではバークレーソケットsend()の機能が必要以上のデータを送信しないことがあります。 Rubyソケットはバークレーソケット上の非常に薄いラッパーなので、AFAIK Socket#sendはバークレーソケットsend()とまったく同じように動作します。だから、RubyのTCPソケット経由で完全なメッセージを送信する正しい方法は何ですか? Pythonでは、それはsendall()と呼ばれる特殊な関数です。しかし、Rubyで、私は手動でそのようなコードを記述する必要があります。Rubyソケットの部分書き込みを正しく処理する方法は?

while (sent = sock.send(data, 0) < data.length do 
    data = data[ sent..-1 ] 
end 

答えて

2

IO.writeio.c

io_binwriteを呼び出して終了、と言うruby sourceの関連ビットは、以下の(nlenが最初にあなたのデータの長さに設定されているとoffsetから0であります)

retry: 
arg.offset = offset; 
arg.length = n; 

if (fptr->write_lock) { 
    r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&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を呼び出します。

+0

ありがとう、ちょうど私が必要なもの。 – grigoryvp

0

最近、私は '書き込み' メソッドを使用:

require "socket" 
server = TCPServer.new('localhost', 20000) 
loop do 
    Thread.start(server.accept) do |s| 
    print(s, " is accepted\n") 
    server.write(Time.now) 
    print(server, " is gone\n") 
    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コードを使用していないので、私はこの特定のライブラリに慣れていません。私はこれをすべて間違っていたら私に知らせてください。 danielnegriものに拡大すること

require 'socket' 
sock = TCPSocket.new(host, port) 
@data = "anyThing" 
sock.send(@data, 0) 
+0

'write'が部分送信を処理するという証拠はありますか? – grigoryvp

関連する問題