-
Notifications
You must be signed in to change notification settings - Fork 0
/
design.htm
129 lines (129 loc) · 7.06 KB
/
design.htm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>KEK Online Class Library Design Principle</title>
</head>
<body>
<hr>
<div align=center>
<h2>network データ収集用C++ class libraryの設計方針</h2>
(©2006 Hirofumi Fujii, KEK Online-electronics group)<br>
(Revised: 24-Aug-2006)
</div>
<hr>
[<a href="index.htm">戻る</a>]
<hr>
<h3>はじめに</h3>
<p>この文書は、著者が製作した network データ収集用C++ class library の設計方針について
述べたものである。
<h3>設計方針</h3>
<p>TCP stream や Thread を扱う C++ class library は世の中に既にある。そこで、
本パッケージでは特に凝ったことはしない。できるだけ単純に C の socket library や
thread library を class 化するにとどめる。
<p>
一方 class 化するに当たり、model としたのは 、(実行効率はともかく)programming しやすい
と言われている Java である。特に"JAVAプログラム クイック リファレンス"に掲載されて
いる network の例題がほぼそのまま焼き直せることを強く意識した。
<p>
上記二つの要求を満たすために
<ul>
<li>Socket を扱う class:これは単純に BSD socket library の socket descriptor を隠蔽する
だけに留める。
<li>TCP stream を扱う class:これは socket をメンバーとして持ち、インターフェースは
標準 library の iostreamに近づける。もしくは iostream から派生させる。
<li>Thread を扱う class、これも単純に pthread の start routine と thread descriptor を
隠蔽するだけに留める。
<li>Thread の start routine の隠蔽の仕方は、Java の runnable class を model とする。
</ul>
<hr>
<h3>Socket に関する class</h3>
<p>Socket class に関しては、socket descriptor を隠蔽することを目的とする。従って、用意される
member 関数は原則として、BSD socket library の socket descriptor を除いたものとする。
<p>Socket descriptor は BSD socket library の socket() 関数を使って生成するが、
BSD socket library にはもう一つ socket descriptor を生成する accept() 関数がある。
これは stream 型で listen している socket から生成される。これをどう反映させるかが
class 設計に大きく影響する。大雑把に次の二つの方法が考えられる。
<ul>
<li>空の Socket() を new して、そこへ accept した descriptor を設定し、その pointer を返す。
<li>accept で作成された descriptor を含む Socket そのものを返す。
</ul>
前者の場合、実装は容易である。またメモリの利用効率もよい。但し、ユーザ側では
受け取った pointer に対し、使用が終わったら必ず delete する必要が生じる。これを忘れると
descriptor の未解放が生じる。一方後者の方法では、代入演算子の実装が不可欠となる。
代入を実装するためには socket descriptor のコピーが必要であり、descriptor 資源を
浪費することになる。資源的には無駄が多いと思われる方法であるが、scope からはずれると
自動的に desctructor が呼ばれるので、destructorで close するようにしておけば、ユーザ側での
誤操作は少なくなると期待される。また、thread の独立性を高めるためにも、pointer ではなく
Socket そのものを thread に持たせる方が扱いやすいと考えられる。ここでは後者の方法をとった。
<h3>TCP stream に関する class</h3>
<p><a href="index.htm">前のページ</a>に述べたように、本class は標準libraryのiostreamに
近づけることを指針とする。iostreamから派生させることもできているが、現時点の配布パッケージには
含まれていない。従って、現時点ではmanipulatorの入出力先としては指定できない。
<p>Socket の生成法の違いにより
<ul>
<li><em>TCPClient</em> :socket()+connect()で生成
<li><em>TCPServer</em> :socket()+bind()で生成
<li><em>TCPSocket</em> :accept()で生成
</ul>
の3つのclassを用意した。このうち<em>TCPClinet</em>及び<em>TCPSocket</em>はともに iostream的
な入出力を行うので、<em>TCPBuffer</em>というclassを用意し、それから派生させている。
iostream の用法に合わせるため、std::ios class にある iostateフラグに関する関数のうち
<ul>
<li>operator void*() const
<li>bool operator!() const
<li>bool good() const
<li>bool eof() const
<li>bool fail() const
<li>bool bad() const
</ul>
を用意した。
<p>入力に関して std::istream class との対応を以下の表に示す。
<table border="1">
<tr><td>member function<td>implemented
<tr><td>streamsize gcount() const<td>yes
<tr><td>int get()<td>yes
<tr><td>istream& get(char& c)<td>no
<tr><td>istream& get(char* s, streamsize n)<td>no
<tr><td>istream& get(char* s, streamsize n, char delim)<td>no
<tr><td>istream& getline(char* s, streamsize n)<td>yes
<tr><td>istream& getline(char* s, streamsize n, char delim)<td>no
<tr><td>istream& ignore(streamsize n=1, int delim=traits::eof())<td>delim 無しで実装
<tr><td>int peek()<td>no
<tr><td>istream& read(char* s, streamsize n)<td>yes
<tr><td>int readsome(char* s, streamsize n)<td>no
<tr><td>istream& putback(char c)<td>no
<tr><td>istream& unget()<td>no
<tr><td>int sync()<td>yes
</table>
<p>出力に関しては std::ostream class との対応は以下の通り。
<table border="1">
<tr><td>member function<td>implemented
<tr><td>ostream& put(char c)<td>yes
<tr><td>ostream& write(const char* s, streamsize n)<td>yes
<tr><td>ostream& flush()<td>yes
</table>
<hr>
<h3>Thread 関連 class</h3>
<p><em>Thread</em> class に関しては、start routine と thread desciptor を隠蔽する。
start routine を隠蔽する理由は、一般に start routine は global object
であり、thread で操作したい data object との結びつきをユーザが設定しなければならないために、
ユーザにとって必ずしも使いやすくないからである。
<p>C++ はデータとその操作関数を一体的に
記述できることが利点の一つであるので、これを一体的に扱える設計にした。
この model として Java の runnable class 的に使える設計にした。
<p>
ユーザは基本的に Thread として実行したい関数及びその時に必要となる
data をひとまとめにして Thread class から派生させた class をつくり、
<ul>
<li>Thread として実行される int run() 関数を上書きする。
<li>Thread class の member 関数 start() を呼び出す。
</ul>
とすればよい。
<p>Thread 間での排他制御や同期をとるために、<em>Mutex</em> と <em>Semaphore</em> の
二つの class を用意した。これらはいずれも POSIX の mutex と semaphore に対応
させてある。
<hr>
[<a href="index.htm">戻る</a>]
<hr>
</body>
</html>