sendfile 0.9.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/FILES +1 -1
- data/README.textile +31 -0
- data/ext/extconf.rb +1 -0
- data/ext/sendfile.c +213 -68
- data/sendfile.gemspec +2 -2
- data/test/test_sendfile.rb +53 -0
- metadata +29 -9
- data/README +0 -57
data/FILES
CHANGED
data/README.textile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
h1. Ruby sendfile(2) Interface
|
2
|
+
|
3
|
+
This module allows Ruby programs to access their OS's native
|
4
|
+
<code>sendfile(2)</code> system call from any IO object. Your kernel must
|
5
|
+
export a recognized signature for the <code>sendfile(2)</code> system call
|
6
|
+
to use this module. Currently, that includes Linux, Solaris
|
7
|
+
and FreeBSD.
|
8
|
+
|
9
|
+
h2. Installation
|
10
|
+
|
11
|
+
Download and install the latest package from the rubyforge.org
|
12
|
+
RubyGems repository.
|
13
|
+
|
14
|
+
$ sudo gem install sendfile
|
15
|
+
|
16
|
+
If the tests all pass, you're ready to start using sendfile.
|
17
|
+
|
18
|
+
h2. Usage
|
19
|
+
|
20
|
+
Here's a small example of a use of <code>IO#sendfile</code>.
|
21
|
+
|
22
|
+
require 'socket'
|
23
|
+
require 'rubygems'
|
24
|
+
require 'sendfile'
|
25
|
+
s = TCPSocket.new 'yourdomain.com', 5000
|
26
|
+
File.open 'somefile.txt' { |f| s.sendfile f }
|
27
|
+
s.close
|
28
|
+
|
29
|
+
See the test scripts for more examples on how to use this
|
30
|
+
module.
|
31
|
+
|
data/ext/extconf.rb
CHANGED
data/ext/sendfile.c
CHANGED
@@ -33,11 +33,55 @@
|
|
33
33
|
*/
|
34
34
|
#include <sys/stat.h>
|
35
35
|
#include <sys/types.h>
|
36
|
+
#include <limits.h>
|
36
37
|
#include "ruby.h"
|
37
|
-
#
|
38
|
-
#include "
|
38
|
+
#ifdef HAVE_RUBY_IO_H
|
39
|
+
# include "ruby/io.h"
|
40
|
+
#else
|
41
|
+
# include "rubyio.h"
|
42
|
+
#endif
|
43
|
+
#include <unistd.h>
|
44
|
+
#include <fcntl.h>
|
39
45
|
#include "config.h"
|
40
46
|
|
47
|
+
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
48
|
+
/*
|
49
|
+
* For non-natively threaded interpreters, do not monopolize the
|
50
|
+
* process and send in smaller chunks. 64K was chosen as it is
|
51
|
+
* half the typical max readahead size in Linux 2.6, giving the
|
52
|
+
* kernel some time to populate the page cache in between
|
53
|
+
* subsequent sendfile() calls.
|
54
|
+
*/
|
55
|
+
# define MAX_SEND_SIZE ((off_t)(0x10000))
|
56
|
+
|
57
|
+
/* (very) partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
|
58
|
+
# include <rubysig.h>
|
59
|
+
# define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
|
60
|
+
typedef void rb_unblock_function_t(void *);
|
61
|
+
typedef VALUE rb_blocking_function_t(void *);
|
62
|
+
static VALUE
|
63
|
+
rb_thread_blocking_region(
|
64
|
+
rb_blocking_function_t *fn, void *data1,
|
65
|
+
rb_unblock_function_t *ubf, void *data2)
|
66
|
+
{
|
67
|
+
VALUE rv;
|
68
|
+
|
69
|
+
TRAP_BEG;
|
70
|
+
rv = fn(data1);
|
71
|
+
TRAP_END;
|
72
|
+
|
73
|
+
return rv;
|
74
|
+
}
|
75
|
+
#else
|
76
|
+
/*
|
77
|
+
* We can release the GVL and block as long as we need to.
|
78
|
+
* Limit this to the maximum ssize_t anyways, since 32-bit machines with
|
79
|
+
* Large File Support can't send more than this number of bytes
|
80
|
+
* in one shot.
|
81
|
+
*/
|
82
|
+
# define MAX_SEND_SIZE ((off_t)LONG_MAX)
|
83
|
+
#endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
|
84
|
+
|
41
85
|
#if defined(RUBY_PLATFORM_FREEBSD)
|
42
86
|
# include <sys/socket.h>
|
43
87
|
# include <sys/uio.h>
|
@@ -48,103 +92,202 @@
|
|
48
92
|
# include <sys/sendfile.h>
|
49
93
|
#endif
|
50
94
|
|
51
|
-
|
52
|
-
|
95
|
+
static size_t count_max(off_t count)
|
96
|
+
{
|
97
|
+
return (size_t)(count > MAX_SEND_SIZE ? MAX_SEND_SIZE : count);
|
98
|
+
}
|
99
|
+
|
100
|
+
struct sendfile_args {
|
101
|
+
int out;
|
102
|
+
int in;
|
103
|
+
off_t off;
|
104
|
+
off_t count;
|
105
|
+
int eof;
|
106
|
+
};
|
107
|
+
|
108
|
+
#if ! HAVE_RB_IO_T
|
109
|
+
# define rb_io_t OpenFile
|
110
|
+
#endif
|
111
|
+
|
112
|
+
#ifdef GetReadFile
|
113
|
+
# define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
|
114
|
+
#else
|
115
|
+
# if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
116
|
+
# define FPTR_TO_FD(fptr) fileno(fptr->f)
|
117
|
+
# else
|
118
|
+
# define FPTR_TO_FD(fptr) fptr->fd
|
119
|
+
# endif
|
120
|
+
#endif
|
121
|
+
|
122
|
+
static int my_rb_fileno(VALUE io)
|
123
|
+
{
|
124
|
+
rb_io_t *fptr;
|
125
|
+
|
126
|
+
GetOpenFile(io, fptr);
|
127
|
+
|
128
|
+
return FPTR_TO_FD(fptr);
|
129
|
+
}
|
53
130
|
|
54
131
|
#if defined(RUBY_PLATFORM_FREEBSD)
|
55
|
-
static
|
132
|
+
static VALUE nogvl_sendfile(void *data)
|
56
133
|
{
|
134
|
+
struct sendfile_args *args = data;
|
57
135
|
int rv;
|
58
|
-
off_t written
|
136
|
+
off_t written;
|
137
|
+
size_t w = count_max(args->count);
|
59
138
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
rb_sys_fail("sendfile");
|
68
|
-
if (!rv)
|
69
|
-
break;
|
70
|
-
rb_thread_select(0, NULL, NULL, NULL, tv);
|
139
|
+
rv = sendfile(args->in, args->out, args->off, args->count,
|
140
|
+
NULL, &written, 0);
|
141
|
+
if (written == 0 && rv == 0) {
|
142
|
+
args->eof = 1;
|
143
|
+
} else {
|
144
|
+
args->off += written;
|
145
|
+
args->count -= written;
|
71
146
|
}
|
72
|
-
|
147
|
+
|
148
|
+
return (VALUE)rv;
|
73
149
|
}
|
74
150
|
#else
|
75
|
-
static
|
151
|
+
static VALUE nogvl_sendfile(void *data)
|
76
152
|
{
|
77
|
-
ssize_t rv
|
78
|
-
|
153
|
+
ssize_t rv;
|
154
|
+
struct sendfile_args *args = data;
|
155
|
+
size_t w = count_max(args->count);
|
156
|
+
|
157
|
+
rv = sendfile(args->out, args->in, &args->off, w);
|
158
|
+
if (rv == 0)
|
159
|
+
args->eof = 1;
|
160
|
+
if (rv > 0)
|
161
|
+
args->count -= rv;
|
162
|
+
|
163
|
+
return (VALUE)rv;
|
164
|
+
}
|
165
|
+
#endif
|
166
|
+
|
167
|
+
static off_t sendfile_full(struct sendfile_args *args)
|
168
|
+
{
|
169
|
+
ssize_t rv;
|
170
|
+
off_t all = args->count;
|
171
|
+
|
79
172
|
while (1) {
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
if (rv < 0 && errno != EAGAIN)
|
84
|
-
rb_sys_fail("sendfile");
|
85
|
-
if (rv > 0)
|
86
|
-
remaining -= rv;
|
87
|
-
if (!remaining)
|
173
|
+
rv = (ssize_t)rb_thread_blocking_region(nogvl_sendfile, args,
|
174
|
+
RUBY_UBF_IO, NULL);
|
175
|
+
if (!args->count)
|
88
176
|
break;
|
89
|
-
|
177
|
+
if (args->eof) {
|
178
|
+
if (all != args->count)
|
179
|
+
break;
|
180
|
+
rb_eof_error();
|
181
|
+
}
|
182
|
+
if (rv < 0 && ! rb_io_wait_writable(args->out))
|
183
|
+
rb_sys_fail("sendfile");
|
90
184
|
}
|
91
|
-
return count;
|
185
|
+
return all - args->count;
|
92
186
|
}
|
93
|
-
#endif
|
94
187
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
188
|
+
static off_t sendfile_nonblock(struct sendfile_args *args)
|
189
|
+
{
|
190
|
+
ssize_t rv;
|
191
|
+
off_t before = args->count;
|
192
|
+
int flags;
|
193
|
+
|
194
|
+
flags = fcntl(args->out, F_GETFL);
|
195
|
+
if (flags == -1)
|
196
|
+
rb_sys_fail("fcntl");
|
197
|
+
if ((flags & O_NONBLOCK) == 0) {
|
198
|
+
if (fcntl(args->out, F_SETFL, flags | O_NONBLOCK) == -1)
|
199
|
+
rb_sys_fail("fcntl");
|
200
|
+
}
|
201
|
+
|
202
|
+
rv = (ssize_t)rb_thread_blocking_region(nogvl_sendfile, args,
|
203
|
+
RUBY_UBF_IO, NULL);
|
204
|
+
if (rv < 0)
|
205
|
+
rb_sys_fail("sendfile");
|
206
|
+
if (args->eof)
|
207
|
+
rb_eof_error();
|
208
|
+
|
209
|
+
return before - args->count;
|
210
|
+
}
|
211
|
+
|
212
|
+
static void convert_args(int argc, VALUE *argv, VALUE self,
|
213
|
+
struct sendfile_args *args)
|
110
214
|
{
|
111
|
-
int i, o;
|
112
|
-
size_t c;
|
113
|
-
off_t off;
|
114
|
-
OpenFile *iptr, *optr;
|
115
215
|
VALUE in, offset, count;
|
116
|
-
struct timeval _sendfile_sleep;
|
117
216
|
|
118
217
|
/* get fds for files involved to pass to sendfile(2) */
|
119
218
|
rb_scan_args(argc, argv, "12", &in, &offset, &count);
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
i = fileno(iptr->f);
|
126
|
-
|
127
|
-
_sendfile_sleep.tv_sec = SENDFILE_PAUSE_SEC;
|
128
|
-
_sendfile_sleep.tv_usec = SENDFILE_PAUSE_USEC;
|
129
|
-
|
219
|
+
in = rb_convert_type(in, T_FILE, "IO", "to_io");
|
220
|
+
args->out = my_rb_fileno(self);
|
221
|
+
args->in = my_rb_fileno(in);
|
222
|
+
args->eof = 0;
|
223
|
+
|
130
224
|
/* determine offset and count parameters */
|
131
|
-
off = (NIL_P(offset)) ? 0 :
|
225
|
+
args->off = (NIL_P(offset)) ? 0 : NUM2OFFT(offset);
|
132
226
|
if (NIL_P(count)) {
|
133
227
|
/* FreeBSD's sendfile() can take 0 as an indication to send
|
134
228
|
* until end of file, but Linux and Solaris can't, and anyway
|
135
229
|
* we need the file size to ensure we send it all in the case
|
136
230
|
* of a non-blocking fd */
|
137
231
|
struct stat s;
|
138
|
-
if (fstat(
|
232
|
+
if (fstat(args->in, &s) == -1)
|
139
233
|
rb_sys_fail("sendfile");
|
140
|
-
|
141
|
-
|
234
|
+
args->count = s.st_size;
|
235
|
+
args->count -= args->off;
|
142
236
|
} else {
|
143
|
-
|
237
|
+
args->count = NUM2OFFT(count);
|
144
238
|
}
|
239
|
+
}
|
240
|
+
|
241
|
+
/* call-seq:
|
242
|
+
* writeIO.sendfile( readIO, offset=0, count=nil) => integer
|
243
|
+
*
|
244
|
+
* Transfers count bytes starting at offset from readIO directly to writeIO
|
245
|
+
* without copying (i.e. invoking the kernel to do it for you).
|
246
|
+
*
|
247
|
+
* If offset is omitted, transfer starts at the beginning of the file.
|
248
|
+
*
|
249
|
+
* If count is omitted, the full length of the file will be sent.
|
250
|
+
*
|
251
|
+
* Returns the number of bytes sent on success. Will throw system error
|
252
|
+
* exception on error. (check man sendfile(2) on your platform for
|
253
|
+
* information on what errors could result and how to handle them)
|
254
|
+
*/
|
255
|
+
static VALUE rb_io_sendfile(int argc, VALUE *argv, VALUE self)
|
256
|
+
{
|
257
|
+
struct sendfile_args args;
|
258
|
+
|
259
|
+
convert_args(argc, argv, self, &args);
|
145
260
|
|
146
261
|
/* now send the file */
|
147
|
-
return
|
262
|
+
return OFFT2NUM(sendfile_full(&args));
|
263
|
+
}
|
264
|
+
|
265
|
+
/* call-seq:
|
266
|
+
* writeIO.sendfile_nonblock(readIO, offset=0, count=nil) => integer
|
267
|
+
*
|
268
|
+
* Transfers count bytes starting at offset from readIO directly to writeIO
|
269
|
+
* without copying (i.e. invoking the kernel to do it for you).
|
270
|
+
*
|
271
|
+
* Unlike IO#sendfile, this will set the O_NONBLOCK flag on writeIO
|
272
|
+
* before calling sendfile(2) and will raise Errno::EAGAIN instead
|
273
|
+
* of blocking. This method is intended for use with non-blocking
|
274
|
+
* event frameworks, including those that rely on Fibers.
|
275
|
+
*
|
276
|
+
* If offset is omitted, transfer starts at the beginning of the file.
|
277
|
+
*
|
278
|
+
* If count is omitted, the full length of the file will be sent.
|
279
|
+
*
|
280
|
+
* Returns the number of bytes sent on success. Will throw system error
|
281
|
+
* exception on error. (check man sendfile(2) on your platform for
|
282
|
+
* information on what errors could result and how to handle them)
|
283
|
+
*/
|
284
|
+
static VALUE rb_io_sendfile_nonblock(int argc, VALUE *argv, VALUE self)
|
285
|
+
{
|
286
|
+
struct sendfile_args args;
|
287
|
+
|
288
|
+
convert_args(argc, argv, self, &args);
|
289
|
+
|
290
|
+
return OFFT2NUM(sendfile_nonblock(&args));
|
148
291
|
}
|
149
292
|
|
150
293
|
/* Interface to the UNIX sendfile(2) system call. Should work on FreeBSD,
|
@@ -153,5 +296,7 @@ static VALUE rb_io_sendfile(int argc, VALUE *argv, VALUE self)
|
|
153
296
|
void Init_sendfile(void)
|
154
297
|
{
|
155
298
|
rb_define_method(rb_cIO, "sendfile", rb_io_sendfile, -1);
|
299
|
+
rb_define_method(rb_cIO, "sendfile_nonblock",
|
300
|
+
rb_io_sendfile_nonblock, -1);
|
156
301
|
}
|
157
302
|
|
data/sendfile.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
spec = Gem::Specification.new do |gs|
|
4
4
|
gs.name = 'sendfile'
|
5
|
-
gs.version = '0.
|
5
|
+
gs.version = '1.0.0'
|
6
6
|
gs.summary = 'Ruby interface to sendfile(2) system call'
|
7
7
|
gs.description = <<-EOF
|
8
8
|
Allows Ruby programs to access sendfile(2) functionality on
|
@@ -19,7 +19,7 @@ EOF
|
|
19
19
|
gs.extensions << 'ext/extconf.rb'
|
20
20
|
|
21
21
|
gs.has_rdoc = true
|
22
|
-
gs.extra_rdoc_files = %w(README)
|
22
|
+
gs.extra_rdoc_files = %w(README.textile)
|
23
23
|
gs.required_ruby_version = '>= 1.8.0'
|
24
24
|
end
|
25
25
|
|
data/test/test_sendfile.rb
CHANGED
@@ -170,5 +170,58 @@ class TestSendfile < Test::Unit::TestCase
|
|
170
170
|
assert_equal data.size, read.size
|
171
171
|
assert_equal data, read
|
172
172
|
end
|
173
|
+
|
174
|
+
def test_sendfile_nonblock
|
175
|
+
c, s = UNIXSocket.pair
|
176
|
+
nr_sent = 0
|
177
|
+
assert_raises(Errno::EAGAIN) do
|
178
|
+
loop do
|
179
|
+
nr_sent += c.sendfile_nonblock @small
|
180
|
+
end
|
181
|
+
end
|
182
|
+
c.close
|
183
|
+
nr_read = s.read.size
|
184
|
+
s.close
|
185
|
+
assert_equal nr_read, nr_sent
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_tempfile
|
189
|
+
tmp = Tempfile.new ''
|
190
|
+
tmp.write @small_data
|
191
|
+
tmp.rewind
|
192
|
+
sent, read = __do_sendfile(tmp)
|
193
|
+
assert_equal @small_data.size, sent
|
194
|
+
assert_equal @small_data.size, read.size
|
195
|
+
assert_equal @small_data, read
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_invalid_file
|
199
|
+
assert_raises(TypeError) { __do_sendfile(:hello) }
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_sendfile_too_big_eof
|
203
|
+
sent = read = nil
|
204
|
+
count = @small_data.size * 2
|
205
|
+
s = TCPSocket.new @host, @port
|
206
|
+
sent = s.sendfile @small, nil, count
|
207
|
+
assert_raises(EOFError) do
|
208
|
+
s.sendfile @small, sent, 1
|
209
|
+
end
|
210
|
+
s.close
|
211
|
+
len = @rd.read( 4).unpack( "N")[0]
|
212
|
+
read = @rd.read len
|
213
|
+
assert_equal @small_data.size, sent
|
214
|
+
assert_equal @small_data.size, read.size
|
215
|
+
assert_equal @small_data, read
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_sendfile_nonblock_eof
|
219
|
+
s = TCPSocket.new @host, @port
|
220
|
+
off = @small_data.size
|
221
|
+
assert_raises(EOFError) do
|
222
|
+
s.sendfile_nonblock @small, off, 1
|
223
|
+
end
|
224
|
+
s.close
|
225
|
+
end
|
173
226
|
end # class TestSendfile
|
174
227
|
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sendfile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Toby DiPasquale
|
@@ -9,21 +15,25 @@ autorequire: sendfile
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2010-06-26 00:00:00 -04:00
|
13
19
|
default_executable:
|
14
20
|
dependencies: []
|
15
21
|
|
16
|
-
description:
|
22
|
+
description: |
|
23
|
+
Allows Ruby programs to access sendfile(2) functionality on
|
24
|
+
any IO object. Works on Linux, Solaris and FreeBSD with
|
25
|
+
blocking and non-blocking sockets.
|
26
|
+
|
17
27
|
email: toby@cbcg.net
|
18
28
|
executables: []
|
19
29
|
|
20
30
|
extensions:
|
21
31
|
- ext/extconf.rb
|
22
32
|
extra_rdoc_files:
|
23
|
-
- README
|
33
|
+
- README.textile
|
24
34
|
files:
|
25
35
|
- FILES
|
26
|
-
- README
|
36
|
+
- README.textile
|
27
37
|
- LICENSE
|
28
38
|
- ChangeLog
|
29
39
|
- ext/extconf.rb
|
@@ -34,29 +44,39 @@ files:
|
|
34
44
|
- sendfile.gemspec
|
35
45
|
has_rdoc: true
|
36
46
|
homepage:
|
47
|
+
licenses: []
|
48
|
+
|
37
49
|
post_install_message:
|
38
50
|
rdoc_options: []
|
39
51
|
|
40
52
|
require_paths:
|
41
53
|
- lib
|
42
54
|
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
43
56
|
requirements:
|
44
57
|
- - ">="
|
45
58
|
- !ruby/object:Gem::Version
|
59
|
+
hash: 55
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 8
|
63
|
+
- 0
|
46
64
|
version: 1.8.0
|
47
|
-
version:
|
48
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
49
67
|
requirements:
|
50
68
|
- - ">="
|
51
69
|
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
52
73
|
version: "0"
|
53
|
-
version:
|
54
74
|
requirements: []
|
55
75
|
|
56
76
|
rubyforge_project: ruby-sendfile
|
57
|
-
rubygems_version: 1.3.
|
77
|
+
rubygems_version: 1.3.7
|
58
78
|
signing_key:
|
59
|
-
specification_version:
|
79
|
+
specification_version: 3
|
60
80
|
summary: Ruby interface to sendfile(2) system call
|
61
81
|
test_files:
|
62
82
|
- test/test_sendfile.rb
|
data/README
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
= Ruby sendfile(2) Interface
|
2
|
-
|
3
|
-
This module allows Ruby programs to access their OS's native
|
4
|
-
sendfile(2) system call from any IO object. Your kernel must
|
5
|
-
export a recognized signature for the sendfile(2) system call
|
6
|
-
to use this module. Currently, that includes Linux, Solaris
|
7
|
-
and FreeBSD.
|
8
|
-
|
9
|
-
== Installation
|
10
|
-
|
11
|
-
Download and install the latest package from the rubyforge.org
|
12
|
-
RubyGems repository.
|
13
|
-
|
14
|
-
gem install sendfile --remote
|
15
|
-
gem check sendfile --test
|
16
|
-
|
17
|
-
If the tests all pass, you're ready to start using sendfile.
|
18
|
-
|
19
|
-
Or, if you don't have rubygems installed, you can install by
|
20
|
-
hand by downloading the tarball:
|
21
|
-
|
22
|
-
tar xzvf ruby-sendfile-<latest>.tar.gz
|
23
|
-
cd ruby-sendfile-<latest>/ext
|
24
|
-
ruby extconf.rb
|
25
|
-
make
|
26
|
-
sudo make install
|
27
|
-
|
28
|
-
You can then run the tests with:
|
29
|
-
|
30
|
-
ruby test/test_*.rb
|
31
|
-
|
32
|
-
== Usage
|
33
|
-
|
34
|
-
Here's a small example of a use of IO#sendfile.
|
35
|
-
|
36
|
-
require 'socket'
|
37
|
-
require 'rubygems'
|
38
|
-
require 'sendfile'
|
39
|
-
|
40
|
-
s = TCPSocket.new 'yourdomain.com', 5000
|
41
|
-
File.open 'somefile.txt' { |f| s.sendfile f }
|
42
|
-
s.close
|
43
|
-
|
44
|
-
See the test scripts for more examples on how to use this
|
45
|
-
module.
|
46
|
-
|
47
|
-
== Contact Information
|
48
|
-
|
49
|
-
This project's homepage is:
|
50
|
-
|
51
|
-
http://rubyforge.org/projects/ruby-sendfile
|
52
|
-
|
53
|
-
Thereupon are additional resources, such as news and forums
|
54
|
-
can be found for working out any issues you may have with this
|
55
|
-
module. In the last case, you can email questions or patches
|
56
|
-
to toby@cbcg.net.
|
57
|
-
|