win32-pipe 0.2.2 → 0.3.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.
@@ -1,33 +1,33 @@
1
- #########################################################################
2
- # example_server.rb
3
- #
4
- # A simple named pipe server. Start this up in its own terminal window.
5
- # You may have to use the task manager to kill it if you don't connect
6
- # with the test client program.
7
- #
8
- # You can start this server with the 'rake example_server' task. Modify
9
- # this code as you see fit.
10
- #########################################################################
11
- require 'win32/pipe'
12
- include Win32
13
-
14
- Thread.new { loop { sleep 0.01 } } # Allow Ctrl-C
15
-
16
- puts "VERSION: " + Pipe::VERSION
17
-
18
- # Block form
19
- Pipe::Server.new('foo') do |pipe|
20
- pipe.connect
21
- data = pipe.read
22
- puts "Got [#{data}]"
23
- pipe.write "Thanks for the data!"
24
- end
25
-
26
- # Non-block form
27
- #pserver = Pipe::Server.new('foo')
28
- #pserver.connect # put server in wait connect
29
- #data = pserver.read
30
- #puts "Got [#{data}]"
31
- #pserver.write("Thanks for the data!")
32
- #pserver.disconnect
1
+ #########################################################################
2
+ # example_server.rb
3
+ #
4
+ # A simple named pipe server. Start this up in its own terminal window.
5
+ # You may have to use the task manager to kill it if you don't connect
6
+ # with the test client program.
7
+ #
8
+ # You can start this server with the 'rake example_server' task. Modify
9
+ # this code as you see fit.
10
+ #########################################################################
11
+ require 'win32/pipe'
12
+ include Win32
13
+
14
+ Thread.new { loop { sleep 0.01 } } # Allow Ctrl-C
15
+
16
+ puts "VERSION: " + Pipe::VERSION
17
+
18
+ # Block form
19
+ Pipe::Server.new('foo') do |pipe|
20
+ pipe.connect
21
+ data = pipe.read
22
+ puts "Got [#{data}]"
23
+ pipe.write "Thanks for the data!"
24
+ end
25
+
26
+ # Non-block form
27
+ #pserver = Pipe::Server.new('foo')
28
+ #pserver.connect # put server in wait connect
29
+ #data = pserver.read
30
+ #puts "Got [#{data}]"
31
+ #pserver.write("Thanks for the data!")
32
+ #pserver.disconnect
33
33
  #pserver.close
@@ -1,100 +1,100 @@
1
- #######################################################################
2
- # example_server_async.rb
3
- #
4
- # A simple, asynchronous named pipe server. Start this up in its own
5
- # terminal window. You can run this program via the
6
- # 'rake example_async_server' task.
7
- #######################################################################
8
- require 'win32/pipe'
9
- include Win32
10
-
11
- puts "VERSION: " + Pipe::VERSION
12
-
13
- Thread.new { loop { sleep 0.01 } } # Allow Ctrl-C
14
-
15
- CONNECTING_STATE = 0
16
- READING_STATE = 1
17
- WRITING_STATE = 2
18
-
19
- class MyPipe < Pipe::Server
20
- def connected
21
- puts "connected"
22
- @state = READING_STATE
23
- end
24
-
25
- def read_complete
26
- puts "read_complete"
27
- puts "Got [#{buffer}]"
28
- @state = WRITING_STATE
29
- end
30
-
31
- def write_complete
32
- puts "write_complete"
33
- disconnect
34
- @state = CONNECTING_STATE
35
- end
36
-
37
- def reconnect
38
- disconnect
39
- mainloop
40
- end
41
-
42
- def mainloop
43
- @state = CONNECTING_STATE
44
- while true
45
- if wait(1) # wait for 1 second
46
- if pending? # IO is pending
47
- case @state
48
- when CONNECTING_STATE
49
- connected
50
- when READING_STATE
51
- if transferred == 0
52
- reconnect
53
- break
54
- end
55
- read_complete
56
- when WRITING_STATE
57
- if transferred != length
58
- reconnect
59
- break
60
- end
61
- write_complete
62
- end
63
- end
64
-
65
- case @state
66
- when CONNECTING_STATE
67
- if connect
68
- connected
69
- end
70
- when READING_STATE
71
- if read
72
- if !pending?
73
- read_complete
74
- end
75
- else
76
- reconnect
77
- end
78
- when WRITING_STATE
79
- if write("Thanks for the data!")
80
- if not pending?
81
- write_complete
82
- end
83
- else
84
- reconnect
85
- break
86
- end
87
- end
88
- end
89
-
90
- sleep(1)
91
- puts "pipe server is running"
92
- end
93
- end
94
- end
95
-
96
- flags = Pipe::ACCESS_DUPLEX | Pipe::OVERLAPPED
97
-
98
- MyPipe.new('foo', 0, flags) do |pipe|
99
- pipe.mainloop
100
- end
1
+ #######################################################################
2
+ # example_server_async.rb
3
+ #
4
+ # A simple, asynchronous named pipe server. Start this up in its own
5
+ # terminal window. You can run this program via the
6
+ # 'rake example_async_server' task.
7
+ #######################################################################
8
+ require 'win32/pipe'
9
+ include Win32
10
+
11
+ puts "VERSION: " + Pipe::VERSION
12
+
13
+ Thread.new { loop { sleep 0.01 } } # Allow Ctrl-C
14
+
15
+ CONNECTING_STATE = 0
16
+ READING_STATE = 1
17
+ WRITING_STATE = 2
18
+
19
+ class MyPipe < Pipe::Server
20
+ def connected
21
+ puts "connected"
22
+ @state = READING_STATE
23
+ end
24
+
25
+ def read_complete
26
+ puts "read_complete"
27
+ puts "Got [#{buffer}]"
28
+ @state = WRITING_STATE
29
+ end
30
+
31
+ def write_complete
32
+ puts "write_complete"
33
+ disconnect
34
+ @state = CONNECTING_STATE
35
+ end
36
+
37
+ def reconnect
38
+ disconnect
39
+ mainloop
40
+ end
41
+
42
+ def mainloop
43
+ @state = CONNECTING_STATE
44
+ while true
45
+ if wait(1) # wait for 1 second
46
+ if pending? # IO is pending
47
+ case @state
48
+ when CONNECTING_STATE
49
+ connected
50
+ when READING_STATE
51
+ if transferred == 0
52
+ reconnect
53
+ break
54
+ end
55
+ read_complete
56
+ when WRITING_STATE
57
+ if transferred != length
58
+ reconnect
59
+ break
60
+ end
61
+ write_complete
62
+ end
63
+ end
64
+
65
+ case @state
66
+ when CONNECTING_STATE
67
+ if connect
68
+ connected
69
+ end
70
+ when READING_STATE
71
+ if read
72
+ if !pending?
73
+ read_complete
74
+ end
75
+ else
76
+ reconnect
77
+ end
78
+ when WRITING_STATE
79
+ if write("Thanks for the data!")
80
+ if not pending?
81
+ write_complete
82
+ end
83
+ else
84
+ reconnect
85
+ break
86
+ end
87
+ end
88
+ end
89
+
90
+ sleep(1)
91
+ puts "pipe server is running"
92
+ end
93
+ end
94
+ end
95
+
96
+ flags = Pipe::ACCESS_DUPLEX | Pipe::OVERLAPPED
97
+
98
+ MyPipe.new('foo', 0, flags) do |pipe|
99
+ pipe.mainloop
100
+ end
data/lib/win32/pipe.rb CHANGED
@@ -1,254 +1,251 @@
1
- require 'windows/pipe'
2
- require 'windows/synchronize'
3
- require 'windows/handle'
4
- require 'windows/file'
5
- require 'windows/error'
6
-
7
- # The Win32 module serves as a namespace only.
8
- module Win32
9
- # The Pipe class is an abstract base class for the Pipe::Server and
10
- # Pipe::Client classes. Do not use this directly.
11
- #
12
- class Pipe
13
- include Windows::Pipe
14
- include Windows::Synchronize
15
- include Windows::Handle
16
- include Windows::File
17
- include Windows::Error
18
-
19
- # Error typically raised if any of the Pipe methods fail.
20
- class Error < StandardError; end
21
-
22
- # The version of this library
23
- VERSION = '0.2.2'
24
-
25
- PIPE_BUFFER_SIZE = 512 #:nodoc:
26
- PIPE_TIMEOUT = 5000 #:nodoc:
27
-
28
- # Blocking mode is enabled
29
- WAIT = PIPE_WAIT
30
-
31
- # Nonblocking mode is enabled
32
- NOWAIT = PIPE_NOWAIT
33
-
34
- # The pipe is bi-directional. Both server and client processes can read
35
- # from and write to the pipe.
36
- ACCESS_DUPLEX = PIPE_ACCESS_DUPLEX
37
-
38
- # The flow of data in the pipe goes from client to server only.
39
- ACCESS_INBOUND = PIPE_ACCESS_INBOUND
40
-
41
- # The flow of data in the pipe goes from server to client only.
42
- ACCESS_OUTBOUND = PIPE_ACCESS_OUTBOUND
43
-
44
- # Data is written to the pipe as a stream of bytes.
45
- TYPE_BYTE = PIPE_TYPE_BYTE
46
-
47
- # Data is written to the pipe as a stream of messages.
48
- TYPE_MESSAGE = PIPE_TYPE_MESSAGE
49
-
50
- # Data is read from the pipe as a stream of bytes.
51
- READMODE_BYTE = PIPE_READMODE_BYTE
52
-
53
- # Data is read from the pipe as a stream of messages.
54
- READMODE_MESSAGE = PIPE_READMODE_MESSAGE
55
-
56
- # All instances beyond the first will fail with access denied errors.
57
- FIRST_PIPE_INSTANCE = FILE_FLAG_FIRST_PIPE_INSTANCE
58
-
59
- # Functions do not return until the data is written across the network.
60
- WRITE_THROUGH = FILE_FLAG_WRITE_THROUGH
61
-
62
- # Overlapped mode enables asynchronous communication.
63
- OVERLAPPED = FILE_FLAG_OVERLAPPED
64
-
65
- # The default pipe mode
66
- DEFAULT_PIPE_MODE = NOWAIT
67
-
68
- # The default open mode
69
- DEFAULT_OPEN_MODE = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH
70
-
71
- # The data still in the pipe's buffer
72
- attr_reader :buffer
73
-
74
- # The number of bytes to be written to the pipe.
75
- attr_reader :size
76
-
77
- # The number of characters that are actually transferred over the pipe.
78
- attr_reader :transferred
79
-
80
- # The full name of the pipe, e.g. "\\\\.\\pipe\\my_pipe"
81
- attr_reader :name
82
-
83
- # The pipe mode of the pipe.
84
- attr_reader :open_mode
85
-
86
- # The open mode of the pipe.
87
- attr_reader :pipe_mode
88
-
89
- # Abstract initializer for base class. This handles automatic prepending
90
- # of '\\.\pipe\' to each named pipe so that you don't have to. Don't
91
- # use this directly. Add the full implementation in subclasses.
92
- #
93
- # The default pipe mode is PIPE_WAIT.
94
- #
95
- # The default open mode is FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH.
96
- #
97
- def initialize(name, pipe_mode = DEFAULT_PIPE_MODE, open_mode = DEFAULT_OPEN_MODE)
98
- @name = "\\\\.\\pipe\\" + name
99
-
100
- @pipe_mode = pipe_mode.nil? ? DEFAULT_PIPE_MODE : pipe_mode
101
- @open_mode = open_mode.nil? ? DEFAULT_OPEN_MODE : open_mode
102
-
103
- @pipe = nil
104
- @pending_io = false
105
- @buffer = 0.chr * PIPE_BUFFER_SIZE
106
- @size = 0
107
- @overlapped = 0.chr * 20 # sizeof(OVERLAPPED)
108
- @transferred = 0
109
- @asynchronous = false
110
-
111
- if open_mode & FILE_FLAG_OVERLAPPED > 0
112
- @asynchronous = true
113
- end
114
-
115
- if @asynchronous
116
- @event = CreateEvent(nil, true, true, nil)
117
- @overlapped[16, 4] = [@event].pack('L')
118
- end
119
- end
120
-
121
- # Disconnects the pipe.
122
- def disconnect
123
- DisconnectNamedPipe(@pipe)
124
- end
125
-
126
- # Closes the pipe.
127
- #
128
- def close
129
- CloseHandle(@pipe)
130
- end
131
-
132
- # Returns whether or not there is a pending IO operation on the pipe.
133
- #
134
- def pending?
135
- @pending_io
136
- end
137
-
138
- # Returns whether or not the pipe is asynchronous.
139
- #
140
- def asynchronous?
141
- @asynchronous
142
- end
143
-
144
- # Reads data from the pipe. You can read data from either end of a named
145
- # pipe.
146
- #
147
- def read
148
- bytes = [0].pack('L')
149
- @buffer = 0.chr * PIPE_BUFFER_SIZE
150
-
151
- if @asynchronous
152
- bool = ReadFile(@pipe, @buffer, @buffer.size, bytes, @overlapped)
153
-
154
- bytes_read = bytes.unpack('L').first
155
-
156
- if bool && bytes_read > 0
157
- @pending_io = false
158
- @buffer = @buffer[0, bytes_read]
159
- return true
160
- end
161
-
162
- error = GetLastError()
163
- if !bool && error == ERROR_IO_PENDING
164
- @pending_io = true
165
- return true
166
- end
167
-
168
- return false
169
- else
170
- unless ReadFile(@pipe, @buffer, @buffer.size, bytes, nil)
171
- raise Error, get_last_error
172
- end
173
- end
174
-
175
- @buffer.unpack("A*")
176
- end
177
-
178
- # Writes 'data' to the pipe. You can write data to either end of a
179
- # named pipe.
180
- #
181
- def write(data)
182
- @buffer = data
183
- @size = data.size
184
- bytes = [0].pack('L')
185
-
186
- if @asynchronous
187
- bool = WriteFile(@pipe, @buffer, @buffer.size, bytes, @overlapped)
188
-
189
- bytes_written = bytes.unpack('L').first
190
-
191
- if bool && bytes_written > 0
192
- @pending_io = false
193
- return true
194
- end
195
-
196
- error = GetLastError()
197
-
198
- if !bool && error == ERROR_IO_PENDING
199
- @pending_io = true
200
- return true
201
- end
202
-
203
- return false
204
- else
205
- unless WriteFile(@pipe, @buffer, @buffer.size, bytes, 0)
206
- raise Error, get_last_error
207
- end
208
-
209
- return true
210
- end
211
- end
212
-
213
- # Returns the pipe object if an event (such as a client connection)
214
- # occurs within the +max_time+ specified (in seconds). Otherwise, it
215
- # returns false.
216
- #
217
- def wait(max_time = nil)
218
- unless @asynchronous
219
- raise Error, 'cannot wait in synchronous (blocking) mode'
220
- end
221
-
222
- max_time = max_time ? max_time * 1000 : INFINITE
223
-
224
- wait = WaitForSingleObject(@event, max_time)
225
-
226
- if wait == WAIT_TIMEOUT
227
- return false
228
- else
229
- if wait != WAIT_OBJECT_0
230
- raise Error, get_last_error
231
- end
232
- end
233
-
234
- if @pending_io
235
- transferred = [0].pack('L')
236
- bool = GetOverlappedResult(@pipe, @overlapped, transferred, false)
237
-
238
- unless bool
239
- raise Error, get_last_error
240
- end
241
-
242
- @transferred = transferred.unpack('L')[0]
243
- @buffer = @buffer[0, @transferred]
244
- end
245
-
246
- self
247
- end
248
-
249
- alias length size
250
- end
251
- end
252
-
253
- require 'win32/pipe/server'
254
- require 'win32/pipe/client'
1
+ require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'constants')
2
+ require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'functions')
3
+
4
+ # The Win32 module serves as a namespace only.
5
+ module Win32
6
+ # The Pipe class is an abstract base class for the Pipe::Server and
7
+ # Pipe::Client classes. Do not use this directly.
8
+ #
9
+ class Pipe
10
+ include Windows::Constants
11
+ include Windows::Functions
12
+
13
+ # Error raised when anything other than a SystemCallError occurs.
14
+ class Error < StandardError; end
15
+
16
+ # The version of this library
17
+ VERSION = '0.3.0'
18
+
19
+ PIPE_BUFFER_SIZE = 512 #:nodoc:
20
+ PIPE_TIMEOUT = 5000 #:nodoc:
21
+
22
+ # Blocking mode is enabled
23
+ WAIT = PIPE_WAIT
24
+
25
+ # Nonblocking mode is enabled
26
+ NOWAIT = PIPE_NOWAIT
27
+
28
+ # The pipe is bi-directional. Both server and client processes can read
29
+ # from and write to the pipe.
30
+ ACCESS_DUPLEX = PIPE_ACCESS_DUPLEX
31
+
32
+ # The flow of data in the pipe goes from client to server only.
33
+ ACCESS_INBOUND = PIPE_ACCESS_INBOUND
34
+
35
+ # The flow of data in the pipe goes from server to client only.
36
+ ACCESS_OUTBOUND = PIPE_ACCESS_OUTBOUND
37
+
38
+ # Data is written to the pipe as a stream of bytes.
39
+ TYPE_BYTE = PIPE_TYPE_BYTE
40
+
41
+ # Data is written to the pipe as a stream of messages.
42
+ TYPE_MESSAGE = PIPE_TYPE_MESSAGE
43
+
44
+ # Data is read from the pipe as a stream of bytes.
45
+ READMODE_BYTE = PIPE_READMODE_BYTE
46
+
47
+ # Data is read from the pipe as a stream of messages.
48
+ READMODE_MESSAGE = PIPE_READMODE_MESSAGE
49
+
50
+ # All instances beyond the first will fail with access denied errors.
51
+ FIRST_PIPE_INSTANCE = FILE_FLAG_FIRST_PIPE_INSTANCE
52
+
53
+ # Functions do not return until the data is written across the network.
54
+ WRITE_THROUGH = FILE_FLAG_WRITE_THROUGH
55
+
56
+ # Overlapped mode enables asynchronous communication.
57
+ OVERLAPPED = FILE_FLAG_OVERLAPPED
58
+
59
+ # The default pipe mode
60
+ DEFAULT_PIPE_MODE = NOWAIT
61
+
62
+ # The default open mode
63
+ DEFAULT_OPEN_MODE = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH
64
+
65
+ # The data still in the pipe's buffer
66
+ attr_reader :buffer
67
+
68
+ # The number of bytes to be written to the pipe.
69
+ attr_reader :size
70
+
71
+ # The number of characters that are actually transferred over the pipe.
72
+ attr_reader :transferred
73
+
74
+ # The full name of the pipe, e.g. "\\\\.\\pipe\\my_pipe"
75
+ attr_reader :name
76
+
77
+ # The pipe mode of the pipe.
78
+ attr_reader :open_mode
79
+
80
+ # The open mode of the pipe.
81
+ attr_reader :pipe_mode
82
+
83
+ # Abstract initializer for base class. This handles automatic prepending
84
+ # of '\\.\pipe\' to each named pipe so that you don't have to. Don't
85
+ # use this directly. Add the full implementation in subclasses.
86
+ #
87
+ # The default pipe mode is PIPE_WAIT.
88
+ #
89
+ # The default open mode is FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH.
90
+ #
91
+ def initialize(name, pipe_mode = DEFAULT_PIPE_MODE, open_mode = DEFAULT_OPEN_MODE)
92
+ @name = "\\\\.\\pipe\\" + name
93
+
94
+ @pipe_mode = pipe_mode.nil? ? DEFAULT_PIPE_MODE : pipe_mode
95
+ @open_mode = open_mode.nil? ? DEFAULT_OPEN_MODE : open_mode
96
+
97
+ @pipe = nil
98
+ @pending_io = false
99
+ @buffer = 0.chr * PIPE_BUFFER_SIZE
100
+ @size = 0
101
+ @overlapped = 0.chr * 20 # sizeof(OVERLAPPED)
102
+ @transferred = 0
103
+ @asynchronous = false
104
+
105
+ if open_mode & FILE_FLAG_OVERLAPPED > 0
106
+ @asynchronous = true
107
+ end
108
+
109
+ if @asynchronous
110
+ @event = CreateEvent(nil, true, true, nil)
111
+ @overlapped[16, 4] = [@event].pack('L')
112
+ end
113
+ end
114
+
115
+ # Disconnects the pipe.
116
+ def disconnect
117
+ DisconnectNamedPipe(@pipe) if @pipe
118
+ end
119
+
120
+ # Closes the pipe.
121
+ #
122
+ def close
123
+ CloseHandle(@pipe) if @pipe
124
+ end
125
+
126
+ # Returns whether or not there is a pending IO operation on the pipe.
127
+ #
128
+ def pending?
129
+ @pending_io
130
+ end
131
+
132
+ # Returns whether or not the pipe is asynchronous.
133
+ #
134
+ def asynchronous?
135
+ @asynchronous
136
+ end
137
+
138
+ # Reads data from the pipe. You can read data from either end of a named
139
+ # pipe.
140
+ #
141
+ def read
142
+ bytes = FFI::MemoryPointer.new(:ulong)
143
+ @buffer = 0.chr * PIPE_BUFFER_SIZE
144
+
145
+ raise Error, "no pipe created" unless @pipe
146
+
147
+ if @asynchronous
148
+ bool = ReadFile(@pipe, @buffer, @buffer.size, bytes, @overlapped)
149
+ error = GetLastError()
150
+
151
+ bytes_read = bytes.read_ulong
152
+
153
+ if bool && bytes_read > 0
154
+ @pending_io = false
155
+ @buffer = @buffer[0, bytes_read]
156
+ return true
157
+ end
158
+
159
+ if !bool && error == ERROR_IO_PENDING
160
+ @pending_io = true
161
+ return true
162
+ end
163
+
164
+ return false
165
+ else
166
+ unless ReadFile(@pipe, @buffer, @buffer.size, bytes, nil)
167
+ raise SystemCallError.new("ReadFile", FFI.errno)
168
+ end
169
+ end
170
+
171
+ @buffer.unpack("A*")
172
+ end
173
+
174
+ # Writes 'data' to the pipe. You can write data to either end of a
175
+ # named pipe.
176
+ #
177
+ def write(data)
178
+ @buffer = data
179
+ @size = data.size
180
+ bytes = FFI::MemoryPointer.new(:ulong)
181
+
182
+ raise Error, "no pipe created" unless @pipe
183
+
184
+ if @asynchronous
185
+ bool = WriteFile(@pipe, @buffer, @buffer.size, bytes, @overlapped)
186
+ error = GetLastError()
187
+
188
+ bytes_written = bytes.read_ulong
189
+
190
+ if bool && bytes_written > 0
191
+ @pending_io = false
192
+ return true
193
+ end
194
+
195
+ if !bool && error == ERROR_IO_PENDING
196
+ @pending_io = true
197
+ return true
198
+ end
199
+
200
+ return false
201
+ else
202
+ unless WriteFile(@pipe, @buffer, @buffer.size, bytes, nil)
203
+ raise SystemCallError.new("WriteFile", FFI.errno)
204
+ end
205
+
206
+ return true
207
+ end
208
+ end
209
+
210
+ # Returns the pipe object if an event (such as a client connection)
211
+ # occurs within the +max_time+ specified (in seconds). Otherwise, it
212
+ # returns false.
213
+ #
214
+ def wait(max_time = nil)
215
+ unless @asynchronous
216
+ raise Error, 'cannot wait in synchronous (blocking) mode'
217
+ end
218
+
219
+ max_time = max_time ? max_time * 1000 : INFINITE
220
+
221
+ wait = WaitForSingleObject(@event, max_time)
222
+
223
+ if wait == WAIT_TIMEOUT
224
+ return false
225
+ else
226
+ if wait != WAIT_OBJECT_0
227
+ raise SystemCallError.new("WaitForSingleObject", FFI.errno)
228
+ end
229
+ end
230
+
231
+ if @pending_io
232
+ transferred = FFI::MemoryPointer.new(:ulong)
233
+ bool = GetOverlappedResult(@pipe, @overlapped, transferred, false)
234
+
235
+ unless bool
236
+ raise SystemCallError.new("GetOverlappedResult", FFI.errno)
237
+ end
238
+
239
+ @transferred = transferred.read_ulong
240
+ @buffer = @buffer[0, @transferred]
241
+ end
242
+
243
+ self
244
+ end
245
+
246
+ alias length size
247
+ end
248
+ end
249
+
250
+ require File.join(File.dirname(__FILE__), 'pipe', 'server')
251
+ require File.join(File.dirname(__FILE__), 'pipe', 'client')