source: vscpl/test/testtcpsock.cc@ 38:40ce1c761f69

Last change on this file since 38:40ce1c761f69 was 37:892ba916fd3d, checked in by István Váradi <ivaradi@…>, 2 years ago

TCP socket test program

File size: 13.7 KB
RevLine 
[37]1// Copyright (c) 2012 by István Váradi
2
3// This file is part of libxplcommon, a common utility library for
4// development related to X-Plane
5
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are met:
8
9// 1. Redistributions of source code must retain the above copyright notice, this
10// list of conditions and the following disclaimer.
11// 2. Redistributions in binary form must reproduce the above copyright notice,
12// this list of conditions and the following disclaimer in the documentation
13// and/or other materials provided with the distribution.
14
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26// The views and conclusions contained in the software and documentation are those
27// of the authors and should not be interpreted as representing official policies,
28// either expressed or implied, of the FreeBSD Project.
29
30//------------------------------------------------------------------------------
31
32#include <hu/varadiistvan/scpl/io/Waiter.h>
33#include <hu/varadiistvan/scpl/io/TCPServerSocket.h>
34#include <hu/varadiistvan/scpl/io/TCPAcceptor.h>
35#include <hu/varadiistvan/scpl/io/TCPSocket.h>
36#include <hu/varadiistvan/scpl/io/TCPClientSocket.h>
37#include <hu/varadiistvan/scpl/io/TCPConnector.h>
38#include <hu/varadiistvan/scpl/io/ReadingBuffer.h>
39#include <hu/varadiistvan/scpl/io/WritingBuffer.h>
40#include <hu/varadiistvan/scpl/io/WaitableEvent.h>
41
42#include <hu/varadiistvan/scpl/Thread.h>
43#include <hu/varadiistvan/scpl/PseudoRandom.h>
44
45#include <cstdlib>
46#include <cstdio>
47#include <cassert>
48
49#include <signal.h>
50
51#include <sys/time.h>
52
53//------------------------------------------------------------------------------
54
55using hu::varadiistvan::scpl::io::Waiter;
56using hu::varadiistvan::scpl::io::TCPServerSocket;
57using hu::varadiistvan::scpl::io::TCPAcceptor;
58using hu::varadiistvan::scpl::io::TCPSocket;
59using hu::varadiistvan::scpl::io::TCPClientSocket;
60using hu::varadiistvan::scpl::io::TCPConnector;
61using hu::varadiistvan::scpl::io::ReadingBuffer;
62using hu::varadiistvan::scpl::io::WritingBuffer;
63using hu::varadiistvan::scpl::io::WaitableEvent;
64
65using hu::varadiistvan::scpl::Thread;
66using hu::varadiistvan::scpl::PseudoRandom;
67
68using std::min;
69
70//------------------------------------------------------------------------------
71
72void communicate(ReadingBuffer* readingBuffer, WritingBuffer* writingBuffer,
73 Waiter& waiter, unsigned seed, const char* prefix,
74 WaitableEvent* quitEvent = 0)
75{
76 static const size_t minToWrite = 2076;
77 static const size_t maxToWrite = 1345670;
78
79 static const size_t reportingInterval = 10000;
80
81 static const int sleepThreshold = static_cast<int>(PseudoRandom::MAX * 0.99);
82 static const int sleepRemainder = PseudoRandom::MAX - sleepThreshold;
83 static const unsigned minSleep = 10;
84 static const unsigned maxSleep = 250;
85 static const unsigned sleepRange = maxSleep - minSleep;
86
87 size_t numBytesRead = 0;
88 size_t nextReportRead = reportingInterval;
89 size_t numWriteBlocked = 0;
90 size_t numBytesWritten = 0;
91 size_t nextReportWritten = reportingInterval;
92 size_t numReadBlocked = 0;
93 size_t numMillisSlept = 0;
94
95 bool toQuit = false;
96
97 PseudoRandom random(seed);
98 while(!toQuit) {
99 size_t toWrite = random.nextUnsigned(maxToWrite, minToWrite);
100
101 size_t lastWriteLength = 0;
102 if (writingBuffer!=0) {
103 lastWriteLength = min(writingBuffer->getCapacity(), toWrite);
104 writingBuffer->reset();
105 writingBuffer->addLength(lastWriteLength);
106 }
107
108 while(toWrite>0) {
109 if (quitEvent!=0 && quitEvent->check()) {
110 toQuit = true;
111 break;
112 }
113
114 bool hasPending = false;
115
116 if (writingBuffer!=0) {
117 size_t loopCount = 0;
118 while(toWrite>0) {
119 ++loopCount;
120 if (writingBuffer->write()) {
121 numBytesWritten += lastWriteLength;
122 toWrite -= lastWriteLength;
123
124 if (numBytesWritten>=nextReportWritten) {
125 printf("%s: written %lu bytes with %lu blocking and %lu ms sleeping\n",
126 prefix,
127 static_cast<unsigned long>(numBytesWritten),
128 static_cast<unsigned long>(numWriteBlocked),
129 static_cast<unsigned long>(numMillisSlept));
130 nextReportWritten += reportingInterval;
131 }
132
133 if (toWrite>0) {
134 if (quitEvent!=0 && quitEvent->check()) {
135 toQuit = true;
136 break;
137 } else {
138 lastWriteLength = min(writingBuffer->getCapacity(), toWrite);
139 writingBuffer->addLength(lastWriteLength);
140 if (loopCount>10) {
141 break;
142 }
143 }
144 }
145 } else if (writingBuffer->failed()) {
146 printf("%s: writing failed with error: %lu\n",
147 prefix,
148 static_cast<unsigned long>(writingBuffer->getErrorCode()));
149 toQuit = true;
150 break;
151 } else {
152 ++numWriteBlocked;
153 hasPending = true;
154 break;
155 }
156 }
157 if (toQuit) break;
158 }
159
160 if (readingBuffer!=0) {
161 size_t loopCount = 0;
162 while(true) {
163 ++loopCount;
164 if (readingBuffer->read()) {
165 size_t l = readingBuffer->getLength();
166 if (l==0) {
167 printf("%s: reading encountered end of file\n", prefix);
168 toQuit = true;
169 break;
170 }
171 numBytesRead += l;
172 if (numBytesRead>=nextReportRead) {
173 printf("%s: read %lu bytes with %lu blocking and %lu ms sleeping\n",
174 prefix,
175 static_cast<unsigned long>(numBytesRead),
176 static_cast<unsigned long>(numReadBlocked),
177 static_cast<unsigned long>(numMillisSlept));
178 nextReportRead += reportingInterval;
179 }
180 readingBuffer->reset();
181 if (quitEvent!=0 && quitEvent->check()) {
182 toQuit = true;
183 break;
184 } else if (loopCount>10) {
185 break;
186 }
187 } else if (readingBuffer->failed()) {
188 printf("%s: reading failed with error: %lu\n",
189 prefix,
190 static_cast<unsigned long>(readingBuffer->getErrorCode()));
191 toQuit = true;
192 break;
193 } else {
194 ++numReadBlocked;
195 hasPending = true;
196 break;
197 }
198 }
199 if (toQuit) break;
200 }
201
202 int r = random.next();
203 if (r>=sleepThreshold) {
204 unsigned toSleep = minSleep +
205 static_cast<unsigned>(static_cast<double>(r - sleepThreshold) *
206 sleepRange / sleepRemainder);
207 assert(toSleep>=minSleep);
208 assert(toSleep<maxSleep);
209 Thread::sleep(toSleep);
210 numMillisSlept += toSleep;
211 }
212
213 if (toWrite>0 && hasPending) {
214 waiter.wait();
215 if (waiter.failed()) {
216 printf("%s: waiting failed with error: %lu\n",
217 prefix,
218 static_cast<unsigned long>(waiter.getErrorCode()));
219 toQuit = true;
220 break;
221 }
222 }
223 }
224 }
225
226 printf("%s: written %lu bytes with %lu blocking\n",
227 prefix,
228 static_cast<unsigned long>(numBytesWritten),
229 static_cast<unsigned long>(numWriteBlocked));
230 printf("%s: read %lu bytes with %lu blocking\n",
231 prefix,
232 static_cast<unsigned long>(numBytesRead),
233 static_cast<unsigned long>(numReadBlocked));
234 printf("%s: slept %lu ms\n", prefix,
235 static_cast<unsigned long>(numMillisSlept));
236}
237
238//------------------------------------------------------------------------------
239
240class ServerThread : public Thread
241{
242private:
243 Waiter waiter;
244
245 WaitableEvent event;
246
247public:
248 ServerThread();
249
250 void signal();
251
252 virtual void run();
253};
254
255//------------------------------------------------------------------------------
256
257ServerThread::ServerThread() :
258 event(&waiter)
259{
260}
261
262//------------------------------------------------------------------------------
263
264void ServerThread::signal()
265{
266 event.fire();
267}
268
269//------------------------------------------------------------------------------
270
271void ServerThread::run()
272{
273 unsigned seed = static_cast<unsigned>(time(0)*1.2);
274 printf("ServerThread::run: seed=%u\n", seed);
275
276 TCPServerSocket serverSocket(12345, &waiter);
277 TCPAcceptor& acceptor = serverSocket.getAcceptor();
278
279 bool eventFired = false;
280 while(!acceptor.accept()) {
281 eventFired = event.check();
282 if (eventFired) break;
283 if (acceptor.failed()) {
284 printf("ServerThread::run: acceptor failed...: %lu\n",
285 (unsigned long)acceptor.getErrorCode());
286 return;
287 }
288 printf("ServerThread::run: waiting...\n");
289 waiter.wait();
290 printf("ServerThread::run: waiting done...\n");
291 }
292
293 if (eventFired) {
294 printf("ServerThread::run: waiting done, quitting\n");
295 return;
296 }
297
298 printf("ServerThread::run: waiting done, received connection\n");
299 TCPSocket* socket = acceptor.getSocket();
300
301 communicate(&socket->getReadingBuffer(), &socket->getWritingBuffer(),
302 waiter, seed, "ServerThread", &event);
303
304
305 delete socket;
306}
307
308//------------------------------------------------------------------------------
309//------------------------------------------------------------------------------
310
311class ClientThread : public Thread
312{
313private:
314 Waiter waiter;
315
316 WaitableEvent event;
317
318public:
319 ClientThread();
320
321 void signal();
322
323 virtual void run();
324};
325
326//------------------------------------------------------------------------------
327
328ClientThread::ClientThread() :
329 event(&waiter)
330{
331}
332
333//------------------------------------------------------------------------------
334
335void ClientThread::signal()
336{
337 event.fire();
338}
339
340//------------------------------------------------------------------------------
341
342void ClientThread::run()
343{
344 unsigned seed = static_cast<unsigned>(time(0)*1.8);
345 printf("ClientThread::run: seed=%u\n", seed);
346
347 printf("ClientThread::run: sleeping\n");
348 sleep(500);
349 printf("ClientThread::run: connecting\n");
350
351 TCPClientSocket socket("127.0.0.1", 12345, &waiter);
352
353 TCPConnector& connector = socket.getConnector();
354
355 while(!connector.connect()) {
356 if (connector.failed()) {
357 printf("ClientThread::run: connector failed...: %lu\n",
358 (unsigned long)connector.getErrorCode());
359 return;
360 }
361 printf("ClientThread::run: waiting... waiter=%p\n", &waiter);
362 waiter.wait();
363 printf("ClientThread::run: waiting done\n");
364 }
365
366 printf("ClientThread::run: connected\n");
367
368 communicate(&socket.getReadingBuffer(), &socket.getWritingBuffer(),
369 waiter, seed, "ClientThread", &event);
370}
371
372//------------------------------------------------------------------------------
373//------------------------------------------------------------------------------
374
375int main()
376{
377#if TARGET_API_POSIX
378 signal(SIGPIPE, SIG_IGN);
379#endif
380
381 ServerThread serverThread;
382 ClientThread clientThread;
383
384 printf("Starting threads\n");
385 serverThread.start();
386 clientThread.start();
387
388 Thread::sleep(60000);
389 //Thread::sleep(5000);
390 printf("Signalling the server thread\n");
391 //serverThread.signal();
392 clientThread.signal();
393 printf("Signalled the server thread\n");
394
395 printf("Waiting for the client thread\n");
396 clientThread.join();
397 printf("Waiting for the server thread\n");
398 serverThread.join();
399 printf("Both threads returned\n");
400
401 return 0;
402}
403
404//------------------------------------------------------------------------------
405
406// Local Variables:
407// mode: C++
408// c-basic-offset: 4
409// indent-tabs-mode: nil
410// End:
Note: See TracBrowser for help on using the repository browser.