source: trunk/FACT++/src/fad.cc@ 11570

Last change on this file since 11570 was 11533, checked in by tbretz, 13 years ago
Optimized event creation.
File size: 24.2 KB
Line 
1#include <iostream>
2#include <string>
3#include <boost/asio.hpp>
4#include <boost/bind.hpp>
5#include <boost/lexical_cast.hpp>
6#include <boost/asio/deadline_timer.hpp>
7#include <boost/enable_shared_from_this.hpp>
8
9using boost::lexical_cast;
10
11#include "Time.h"
12#include "Converter.h"
13
14#include "HeadersFAD.h"
15
16#include "dis.hxx"
17#include "Dim.h"
18
19using namespace std;
20using namespace FAD;
21
22namespace ba = boost::asio;
23namespace bs = boost::system;
24namespace dummy = ba::placeholders;
25
26using boost::lexical_cast;
27using ba::ip::tcp;
28
29class tcp_connection;
30
31class Trigger : public DimCommandHandler
32{
33 DimCommand fCmd;
34
35 vector<tcp_connection*> vec;
36
37public:
38 Trigger() : fCmd("FAD/TRIGGER", "I:1", this)
39 {
40 }
41
42 void Add(tcp_connection *ptr)
43 {
44 vec.push_back(ptr);
45 }
46
47 void Remove(tcp_connection *ptr)
48 {
49 vec.erase(find(vec.begin(), vec.end(), ptr));
50 }
51
52 void commandHandler();
53};
54
55// ------------------------------------------------------------------------
56
57class tcp_connection : public ba::ip::tcp::socket, public boost::enable_shared_from_this<tcp_connection>
58{
59public:
60 static Trigger fTrigger;
61
62 const int fBoardId;
63
64 double fStartTime;
65
66 void AsyncRead(ba::mutable_buffers_1 buffers)
67 {
68 ba::async_read(*this, buffers,
69 boost::bind(&tcp_connection::HandleReceivedData, shared_from_this(),
70 dummy::error, dummy::bytes_transferred));
71 }
72
73 void AsyncWrite(ba::ip::tcp::socket *socket, const ba::const_buffers_1 &buffers)
74 {
75 ba::async_write(*socket, buffers,
76 boost::bind(&tcp_connection::HandleSentData, shared_from_this(),
77 dummy::error, dummy::bytes_transferred));
78 }
79 void AsyncWait(ba::deadline_timer &timer, int seconds,
80 void (tcp_connection::*handler)(const bs::error_code&))// const
81 {
82 timer.expires_from_now(boost::posix_time::milliseconds(seconds));
83 timer.async_wait(boost::bind(handler, shared_from_this(), dummy::error));
84 }
85
86 // The constructor is prvate to force the obtained pointer to be shared
87 tcp_connection(ba::io_service& ioservice, int boardid) : ba::ip::tcp::socket(ioservice),
88 fBoardId(boardid), fRamRoi(kNumChannels), fTriggerSendData(ioservice),
89 fTriggerEnabled(false)
90 {
91 fTrigger.Add(this);
92 }
93 void PostTrigger(uint32_t triggerid)
94 {
95 if (fTriggerEnabled)
96 get_io_service().post(boost::bind(&tcp_connection::SendData, this, triggerid));
97 }
98
99 // Callback when writing was successfull or failed
100 void HandleSentData(const boost::system::error_code& error, size_t bytes_transferred)
101 {
102#ifdef DEBUG_TX
103 cout << "Data sent[" << fBoardId << "]: (transmitted=" << bytes_transferred << ") rc=" << error.message() << " (" << error << ")" << endl;
104#endif
105 fOutQueue.pop_front();
106 }
107
108 vector<uint16_t> fBufCommand;
109
110 vector<uint16_t> fCommand;
111
112 FAD::EventHeader fHeader;
113 FAD::EventHeader fRam;
114 FAD::ChannelHeader fChHeader[kNumChannels];
115
116 vector<uint16_t> fRamRoi;
117
118 ba::deadline_timer fTriggerSendData;
119
120 bool fTriggerEnabled;
121 bool fCommandSocket;
122
123 int fSocket;
124
125 deque<vector<uint16_t>> fOutQueue;
126
127 void SendData(uint32_t triggerid)
128 {
129 fHeader.fPackageLength = sizeof(EventHeader)/2+1;
130 fHeader.fEventCounter++;
131 fHeader.fTriggerId = triggerid;
132 fHeader.fTimeStamp = uint32_t((Time(Time::utc).UnixTime()-fStartTime)*10000);
133 fHeader.fFreqRefClock = 997+rand()/(RAND_MAX/7);
134
135 /* Trigger ID
136
137 * Byte[4]: Bit 0: ext1
138 * Byte[4]: Bit 1: ext2
139 * Byte[4]: Bit 2-7: n/40
140 * Byte[5]: Bit 0: LP_1
141 * Byte[5]: Bit 1: LP_2
142 * Byte[5]: Bit 2: Pedestal
143 * Byte[5]: Bit 3:
144 * Byte[5]: Bit 4:
145 * Byte[5]: Bit 5:
146 * Byte[5]: Bit 6:
147 * Byte[5]: Bit 7: TIM source
148
149 */
150
151 for (int i=0; i<FAD::kNumTemp; i++)
152 fHeader.fTempDrs[i] = (42.+fBoardId/40.+float(rand())/RAND_MAX*5)*16;
153
154 // Header, channel header, end delimiter
155 size_t sz = sizeof(fHeader) + kNumChannels*sizeof(FAD::ChannelHeader) + 2;
156 // Data
157 for (int i=0; i<kNumChannels; i++)
158 sz += fChHeader[i].fRegionOfInterest*2;
159
160 vector<uint16_t> evtbuf;
161 evtbuf.reserve(sz);
162
163 for (int i=0; i<kNumChannels; i++)
164 {
165 fChHeader[i].fStartCell = int64_t(1023)*rand()/RAND_MAX;
166
167 vector<int16_t> data(fChHeader[i].fRegionOfInterest, -1024+0x42+i/9+fHeader.fDac[1]/32);
168
169 for (int ii=0; ii<fChHeader[i].fRegionOfInterest; ii++)
170 {
171 const int rel = ii;
172 const int abs = (ii+fChHeader[i].fStartCell)%fChHeader[i].fRegionOfInterest;
173
174 data[rel] += 6.*rand()/RAND_MAX + 5*exp(-rel/10); // sigma=10
175 data[rel] += 15*sin(2*3.1415*abs/512); // sigma=10
176 }
177
178 if (triggerid>0)
179 {
180 int p = 5.*rand()/RAND_MAX+ 20;
181 double rndm = 500.*rand()/RAND_MAX+500;
182 for (int ii=0; ii<fChHeader[i].fRegionOfInterest; ii++)
183 data[ii] += rndm*exp(-0.5*(ii-p)*(ii-p)/25); // sigma=10
184 }
185
186 const vector<uint16_t> buf = fChHeader[i].HtoN();
187
188 evtbuf.insert(evtbuf.end(), buf.begin(), buf.end());
189 evtbuf.insert(evtbuf.end(), data.begin(), data.end());
190
191 fHeader.fPackageLength += sizeof(ChannelHeader)/2;
192 fHeader.fPackageLength += fChHeader[i].fRegionOfInterest;
193 }
194
195 evtbuf.push_back(htons(FAD::kDelimiterEnd));
196
197 const vector<uint16_t> h = fHeader.HtoN();
198
199 evtbuf.insert(evtbuf.begin(), h.begin(), h.end());
200
201 fOutQueue.push_back(evtbuf);
202
203 if (fCommandSocket)
204 AsyncWrite(this, ba::buffer(ba::const_buffer(fOutQueue.back().data(), fOutQueue.back().size()*2)));
205 else
206 {
207 if (fSockets.size()==0)
208 return;
209
210 fSocket++;
211 fSocket %= fSockets.size();
212
213 AsyncWrite(fSockets[fSocket].get(), ba::buffer(ba::const_buffer(fOutQueue.back().data(), fOutQueue.back().size()*2)));
214 }
215 }
216
217 void TriggerSendData(const boost::system::error_code &ec)
218 {
219 if (!is_open())
220 {
221 // For example: Here we could schedule a new accept if we
222 // would not want to allow two connections at the same time.
223 return;
224 }
225
226 if (ec==ba::error::basic_errors::operation_aborted)
227 return;
228
229 // Check whether the deadline has passed. We compare the deadline
230 // against the current time since a new asynchronous operation
231 // may have moved the deadline before this actor had a chance
232 // to run.
233 if (fTriggerSendData.expires_at() > ba::deadline_timer::traits_type::now())
234 return;
235
236 // The deadline has passed.
237 if (fTriggerEnabled)
238 SendData(0);
239
240 AsyncWait(fTriggerSendData, fHeader.fTriggerGeneratorPrescaler, &tcp_connection::TriggerSendData);
241 }
242
243 void HandleReceivedData(const boost::system::error_code& error, size_t bytes_received)
244 {
245 // Do not schedule a new read if the connection failed.
246 if (bytes_received==0)
247 {
248 // Close the connection
249 close();
250 return;
251 }
252
253 // No command received yet
254 if (fCommand.size()==0)
255 {
256 transform(fBufCommand.begin(), fBufCommand.begin()+bytes_received/2,
257 fBufCommand.begin(), ntohs);
258
259 switch (fBufCommand[0])
260 {
261 case kCmdDrsEnable:
262 case kCmdDrsEnable+0x100:
263 fHeader.Enable(FAD::EventHeader::kDenable, fBufCommand[0]==kCmdDrsEnable);
264 cout << "-> DrsEnable " << fBoardId << " " << (fBufCommand[0]==kCmdDrsEnable) << endl;
265 break;
266
267 case kCmdDwrite:
268 case kCmdDwrite+0x100:
269 fHeader.Enable(FAD::EventHeader::kDwrite, fBufCommand[0]==kCmdDwrite);
270 cout << "-> Dwrite " << fBoardId << " " << (fBufCommand[0]==kCmdDwrite) << endl;
271 break;
272
273 case kCmdTriggerLine:
274 case kCmdTriggerLine+0x100:
275 cout << "-> Trigger line " << fBoardId << " " << (fBufCommand[0]==kCmdTriggerLine) << endl;
276 fTriggerEnabled = fBufCommand[0]==kCmdTriggerLine;
277 fHeader.Enable(FAD::EventHeader::kTriggerLine, fTriggerEnabled);
278 break;
279
280 case kCmdSclk:
281 case kCmdSclk+0x100:
282 cout << "-> Sclk " << fBoardId << endl;
283 fHeader.Enable(FAD::EventHeader::kSpiSclk, fBufCommand[0]==kCmdSclk);
284 break;
285
286 case kCmdSrclk:
287 case kCmdSrclk+0x100:
288 cout << "-> Drclk " << fBoardId << endl;
289 break;
290
291 case kCmdRun:
292 case kCmdRun+0x100:
293 fStartTime = Time(Time::utc).UnixTime();
294 cout << "-> Run " << fBoardId << endl;
295 break;
296
297 case kCmdBusy:
298 case kCmdBusy+0x100:
299 cout << "-> Busy " << fBoardId << " " << (fBufCommand[0]==kCmdBusy) << endl;
300 fHeader.Enable(FAD::EventHeader::kBusy, fBufCommand[0]==kCmdBusy);
301 break;
302
303 case kCmdSocket:
304 case kCmdSocket+0x100:
305 cout << "-> Socket " << fBoardId << " " << (fBufCommand[0]==kCmdSocket) << endl;
306 fCommandSocket = fBufCommand[0]==kCmdSocket;
307 fHeader.Enable(FAD::EventHeader::kSock17, !fCommandSocket);
308 break;
309
310 case kCmdContTrigger:
311 case kCmdContTrigger+0x100:
312 if (fBufCommand[0]==kCmdContTrigger)
313 AsyncWait(fTriggerSendData, 0, &tcp_connection::TriggerSendData);
314 else
315 fTriggerSendData.cancel();
316 fHeader.Enable(FAD::EventHeader::kContTrigger, fBufCommand[0]==kCmdContTrigger);
317 cout << "-> ContTrig " << fBoardId << " " << (fBufCommand[0]==kCmdContTrigger) << endl;
318 break;
319
320 case kCmdResetEventCounter:
321 cout << "-> ResetId " << fBoardId << endl;
322 fHeader.fEventCounter = 0;
323 break;
324
325 case kCmdSingleTrigger:
326 cout << "-> Trigger " << fBoardId << endl;
327 SendData(0);
328 break;
329
330 case kCmdWriteExecute:
331 cout << "-> Execute " << fBoardId << endl;
332 memcpy(fHeader.fDac, fRam.fDac, sizeof(fHeader.fDac));
333 for (int i=0; i<kNumChannels; i++)
334 fChHeader[i].fRegionOfInterest = fRamRoi[i];
335 fHeader.fRunNumber = fRam.fRunNumber;
336 break;
337
338 case kCmdWriteRunNumberMSW:
339 fCommand = fBufCommand;
340 break;
341
342 case kCmdWriteRunNumberLSW:
343 fCommand = fBufCommand;
344 break;
345
346 default:
347 if (fBufCommand[0]>=kCmdWriteRoi && fBufCommand[0]<kCmdWriteRoi+kNumChannels)
348 {
349 fCommand.resize(2);
350 fCommand[0] = kCmdWriteRoi;
351 fCommand[1] = fBufCommand[0]-kCmdWriteRoi;
352 break;
353 }
354 if (fBufCommand[0]>= kCmdWriteDac && fBufCommand[0]<kCmdWriteDac+kNumDac)
355 {
356 fCommand.resize(2);
357 fCommand[0] = kCmdWriteDac;
358 fCommand[1] = fBufCommand[0]-kCmdWriteDac;
359 break;
360 }
361 if (fBufCommand[0]==kCmdWriteRate)
362 {
363 fCommand.resize(1);
364 fCommand[0] = kCmdWriteRate;
365 break;
366 }
367
368 cout << "Received b=" << bytes_received << ": " << error.message() << " (" << error << ")" << endl;
369 cout << "Hex:" << Converter::GetHex<uint16_t>(&fBufCommand[0], bytes_received) << endl;
370 return;
371 }
372
373 fBufCommand.resize(1);
374 AsyncRead(ba::buffer(fBufCommand));
375 return;
376 }
377
378 transform(fBufCommand.begin(), fBufCommand.begin()+bytes_received/2,
379 fBufCommand.begin(), ntohs);
380
381 switch (fCommand[0])
382 {
383 case kCmdWriteRunNumberMSW:
384 fRam.fRunNumber &= 0xffff;
385 fRam.fRunNumber |= fBufCommand[0]<<16;
386 cout << "-> Set RunNumber " << fBoardId << " MSW" << endl;
387 break;
388 case kCmdWriteRunNumberLSW:
389 fRam.fRunNumber &= 0xffff0000;
390 fRam.fRunNumber |= fBufCommand[0];
391 cout << "-> Set RunNumber " << fBoardId << " LSW" << endl;
392 break;
393 case kCmdWriteRoi:
394 cout << "-> Set " << fBoardId << " Roi[" << fCommand[1] << "]=" << fBufCommand[0] << endl;
395 //fChHeader[fCommand[1]].fRegionOfInterest = fBufCommand[0];
396 fRamRoi[fCommand[1]] = fBufCommand[0];
397 break;
398
399 case kCmdWriteDac:
400 cout << "-> Set " << fBoardId << " Dac[" << fCommand[1] << "]=" << fBufCommand[0] << endl;
401 fRam.fDac[fCommand[1]] = fBufCommand[0];
402 break;
403
404 case kCmdWriteRate:
405 cout << "-> Set " << fBoardId << " Rate =" << fBufCommand[0] << endl;
406 fHeader.fTriggerGeneratorPrescaler = fBufCommand[0];
407 break;
408 }
409
410 fCommand.resize(0);
411
412 fBufCommand.resize(1);
413 AsyncRead(ba::buffer(fBufCommand));
414 }
415
416public:
417 typedef boost::shared_ptr<tcp_connection> shared_ptr;
418
419 static shared_ptr create(ba::io_service& io_service, int boardid)
420 {
421 return shared_ptr(new tcp_connection(io_service, boardid));
422 }
423
424 void start()
425 {
426 // Ownership of buffer must be valid until Handler is called.
427
428 fTriggerEnabled=false;
429 fCommandSocket=true;
430
431 fHeader.fStartDelimiter = FAD::kDelimiterStart;
432 fHeader.fVersion = 0x104;
433 fHeader.fBoardId = (fBoardId%10) | ((fBoardId/10)<<8);
434 fHeader.fRunNumber = 0;
435 fHeader.fDNA = reinterpret_cast<uint64_t>(this);
436 fHeader.fTriggerGeneratorPrescaler = 100;
437 fHeader.fStatus = 0xf<<12 |
438 FAD::EventHeader::kDenable |
439 FAD::EventHeader::kDwrite |
440 FAD::EventHeader::kDcmLocked |
441 FAD::EventHeader::kDcmReady |
442 FAD::EventHeader::kSpiSclk;
443
444
445 fStartTime = Time(Time::utc).UnixTime();
446
447 for (int i=0; i<kNumChannels; i++)
448 {
449 fChHeader[i].fId = (i%9) | ((i/9)<<4);
450 fChHeader[i].fRegionOfInterest = 0;
451 }
452
453 // Emit something to be written to the socket
454 fBufCommand.resize(1);
455 AsyncRead(ba::buffer(fBufCommand));
456
457// AsyncWait(fTriggerDynData, 1, &tcp_connection::SendDynData);
458
459// AsyncWrite(ba::buffer(ba::const_buffer(&fHeader, sizeof(FTM::Header))));
460// AsyncWait(deadline_, 3, &tcp_connection::check_deadline);
461
462 }
463
464 vector<boost::shared_ptr<ba::ip::tcp::socket>> fSockets;
465
466 ~tcp_connection()
467 {
468 fTrigger.Remove(this);
469 fSockets.clear();
470 }
471
472 void handle_accept(boost::shared_ptr<ba::ip::tcp::socket> socket, int port, const boost::system::error_code&/* error*/)
473 {
474 cout << this << " Added one socket[" << fBoardId << "] " << socket->remote_endpoint().address().to_v4().to_string();
475 cout << ":"<< port << endl;
476 fSockets.push_back(socket);
477 }
478};
479
480Trigger tcp_connection::fTrigger;
481
482void Trigger::commandHandler()
483{
484 if (!getCommand())
485 return;
486
487 for (vector<tcp_connection*>::iterator it=vec.begin();
488 it!=vec.end(); it++)
489 (*it)->PostTrigger(getCommand()->getInt());
490}
491
492
493class tcp_server
494{
495 tcp::acceptor acc0;
496 tcp::acceptor acc1;
497 tcp::acceptor acc2;
498 tcp::acceptor acc3;
499 tcp::acceptor acc4;
500 tcp::acceptor acc5;
501 tcp::acceptor acc6;
502 tcp::acceptor acc7;
503
504 int fBoardId;
505
506public:
507 tcp_server(ba::io_service& ioservice, int port, int board) :
508 acc0(ioservice, tcp::endpoint(tcp::v4(), port)),
509 acc1(ioservice, tcp::endpoint(tcp::v4(), port+1)),
510 acc2(ioservice, tcp::endpoint(tcp::v4(), port+2)),
511 acc3(ioservice, tcp::endpoint(tcp::v4(), port+3)),
512 acc4(ioservice, tcp::endpoint(tcp::v4(), port+4)),
513 acc5(ioservice, tcp::endpoint(tcp::v4(), port+5)),
514 acc6(ioservice, tcp::endpoint(tcp::v4(), port+6)),
515 acc7(ioservice, tcp::endpoint(tcp::v4(), port+7)),
516 fBoardId(board)
517 {
518 // We could start listening for more than one connection
519 // here, but since there is only one handler executed each time
520 // it would not make sense. Before one handle_accept is not
521 // finished no new handle_accept will be called.
522 // Workround: Start a new thread in handle_accept
523 start_accept();
524 }
525
526private:
527 void start_accept(tcp_connection::shared_ptr dest, tcp::acceptor &acc)
528 {
529 boost::shared_ptr<ba::ip::tcp::socket> connection =
530 boost::shared_ptr<ba::ip::tcp::socket>(new ba::ip::tcp::socket(acc.io_service()));
531
532 acc.async_accept(*connection,
533 boost::bind(&tcp_connection::handle_accept,
534 dest, connection,
535 acc.local_endpoint().port(),
536 ba::placeholders::error));
537 }
538
539 void start_accept()
540 {
541 cout << "Start accept[" << fBoardId << "] " << acc0.local_endpoint().port() << "..." << flush;
542 tcp_connection::shared_ptr new_connection = tcp_connection::create(/*acceptor_.*/acc0.io_service(), fBoardId);
543
544 cout << new_connection.get() << " ";
545
546 // This will accept a connection without blocking
547 acc0.async_accept(*new_connection,
548 boost::bind(&tcp_server::handle_accept,
549 this,
550 new_connection,
551 ba::placeholders::error));
552
553 start_accept(new_connection, acc1);
554 start_accept(new_connection, acc2);
555 start_accept(new_connection, acc3);
556 start_accept(new_connection, acc4);
557 start_accept(new_connection, acc5);
558 start_accept(new_connection, acc6);
559 start_accept(new_connection, acc7);
560
561 cout << "start-done." << endl;
562 }
563
564 void handle_accept(tcp_connection::shared_ptr new_connection, const boost::system::error_code& error)
565 {
566 // The connection has been accepted and is now ready to use
567
568 // not installing a new handler will stop run()
569 cout << new_connection.get() << " Handle accept[" << fBoardId << "]["<<new_connection->fBoardId<<"]..." << flush;
570 if (!error)
571 {
572 new_connection->start();
573
574 // The is now an open connection/server (tcp_connection)
575 // we immediatly schedule another connection
576 // This allowed two client-connection at the same time
577 start_accept();
578 }
579 cout << "handle-done." << endl;
580 }
581};
582
583#include "Configuration.h"
584
585void SetupConfiguration(::Configuration &conf)
586{
587 const string n = conf.GetName()+".log";
588
589 po::options_description config("Program options");
590 config.add_options()
591 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
592 ("port,p", var<uint16_t>(4000), "")
593 ("num,n", var<uint16_t>(40), "")
594 ;
595
596 po::positional_options_description p;
597 p.add("port", 1); // The first positional options
598 p.add("num", 1); // The second positional options
599
600 conf.AddEnv("dns", "DIM_DNS_NODE");
601
602 conf.AddOptions(config);
603 conf.SetArgumentPositions(p);
604}
605
606int main(int argc, const char **argv)
607{
608 ::Configuration conf(argv[0]);
609
610 SetupConfiguration(conf);
611
612 po::variables_map vm;
613 try
614 {
615 vm = conf.Parse(argc, argv);
616 }
617#if BOOST_VERSION > 104000
618 catch (po::multiple_occurrences &e)
619 {
620 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
621 return -1;
622 }
623#endif
624 catch (exception& e)
625 {
626 cerr << "Program options invalid due to: " << e.what() << endl;
627 return -1;
628 }
629
630 if (conf.HasVersion() || conf.HasPrint() || conf.HasHelp())
631 return -1;
632
633 Dim::Setup(conf.Get<string>("dns"));
634
635 DimServer::start("FAD");
636
637 //try
638 {
639 ba::io_service io_service;
640
641 const uint16_t n = conf.Get<uint16_t>("num");
642 uint16_t port = conf.Get<uint16_t>("port");
643
644 vector<shared_ptr<tcp_server>> servers;
645
646 for (int i=0; i<n; i++)
647 {
648 shared_ptr<tcp_server> server(new tcp_server(io_service, port, i));
649 servers.push_back(server);
650
651 port += 8;
652 }
653
654 // ba::add_service(io_service, &server);
655 // server.add_service(...);
656 //cout << "Run..." << flush;
657
658 // Calling run() from a single thread ensures no concurrent access
659 // of the handler which are called!!!
660 io_service.run();
661
662 //cout << "end." << endl;
663 }
664 /*catch (std::exception& e)
665 {
666 std::cerr << e.what() << std::endl;
667 }*/
668
669 return 0;
670}
671/* ====================== Buffers ===========================
672
673char d1[128]; ba::buffer(d1));
674std::vector<char> d2(128); ba::buffer(d2);
675boost::array<char, 128> d3; by::buffer(d3);
676
677// --------------------------------
678char d1[128];
679std::vector<char> d2(128);
680boost::array<char, 128> d3;
681
682boost::array<mutable_buffer, 3> bufs1 = {
683 ba::buffer(d1),
684 ba::buffer(d2),
685 ba::buffer(d3) };
686sock.read(bufs1);
687
688std::vector<const_buffer> bufs2;
689bufs2.push_back(boost::asio::buffer(d1));
690bufs2.push_back(boost::asio::buffer(d2));
691bufs2.push_back(boost::asio::buffer(d3));
692sock.write(bufs2);
693
694
695// ======================= Read functions =========================
696
697ba::async_read_until --> delimiter
698
699streambuf buf; // Ensure validity until handler!
700by::async_read(s, buf, ....);
701
702ba::async_read(s, ba:buffer(data, size), handler);
703 // Single buffer
704 boost::asio::async_read(s,
705 ba::buffer(data, size),
706 compl-func --> ba::transfer_at_least(32),
707 handler);
708
709 // Multiple buffers
710boost::asio::async_read(s, buffers,
711 compl-func --> boost::asio::transfer_all(),
712 handler);
713 */
714
715// ================= Others ===============================
716
717 /*
718 strand Provides serialised handler execution.
719 work Class to inform the io_service when it has work to do.
720
721
722io_service::
723dispatch Request the io_service to invoke the given handler.
724poll Run the io_service's event processing loop to execute ready
725 handlers.
726poll_one Run the io_service's event processing loop to execute one ready
727 handler.
728post Request the io_service to invoke the given handler and return
729 immediately.
730reset Reset the io_service in preparation for a subsequent run()
731 invocation.
732run Run the io_service's event processing loop.
733run_one Run the io_service's event processing loop to execute at most
734 one handler.
735stop Stop the io_service's event processing loop.
736wrap Create a new handler that automatically dispatches the wrapped
737 handler on the io_service.
738
739strand:: The io_service::strand class provides the ability to
740 post and dispatch handlers with the guarantee that none
741 of those handlers will execute concurrently.
742
743dispatch Request the strand to invoke the given handler.
744get_io_service Get the io_service associated with the strand.
745post Request the strand to invoke the given handler and return
746 immediately.
747wrap Create a new handler that automatically dispatches the
748 wrapped handler on the strand.
749
750work:: The work class is used to inform the io_service when
751 work starts and finishes. This ensures that the io_service's run() function will not exit while work is underway, and that it does exit when there is no unfinished work remaining.
752get_io_service Get the io_service associated with the work.
753work Constructor notifies the io_service that work is starting.
754
755*/
756
757
Note: See TracBrowser for help on using the repository browser.