東陽の研究ノート
接続を能動的に開始することは、接続を受動的に受け入れることよりも複雑です。
- 一方では、エラー処理は面倒です。
- もう1つの側面は、再試行を検討することです。
ノンブロッキングネットワークプログラミングでは、接続を開始する基本的な方法は、connect(2)を呼び出すことです。ソケットが書き込み可能になると、接続が確立されます。もちろん、これはあらゆる種類のメッセージエラーを処理し、それらをコネクタクラスとしてカプセル化する必要があります。インターフェイスは次のとおりです。
class Connector : boost::noncopyable
{
public:
typedef boost::function<void (int sockfd)> NewConnectionCallback;
Connector(EventLoop* loop, const InetAddress& serverAddr);
~Connector();
void setNewConnectionCallback(const NewConnectionCallback& cb)
{
newConnectionCallback_ = cb; }
void start(); // can be called in any thread
void restart(); // must be called in loop thread
void stop(); // can be called in any thread
const InetAddress& serverAddress() const {
return serverAddr_; }
コネクタの実装における2つ、いくつかの困難
- ソケットは1回限りです。エラーが発生すると(たとえば、相手が接続を拒否した場合)、ソケットを回復することはできず、閉じて再起動することしかできません。オブジェクトのライフサイクル管理に注意を払う必要があります
- エラーコードはaccept(2)とは異なります。
- EAGAINは実際のエラーです。つまり、ローカルのエフェメラルポートが一時的に使い果たされており、ソケットを閉じて、しばらくしてから再試行する必要があります。
- 接続されている戻りコードはEINPROGRESSです。
- また、ソケットが書き込み可能であっても、接続が正常に確立されたとは限らないため、getsockopt(...)を使用して再度確認する必要があります。
- 再試行間隔は徐々に延長する必要があります。たとえば、0.5、1秒、2秒、4秒、最大30秒、つまりバックオフです。これにより、オブジェクトの存続期間の管理が困難になります。runAfterタイミングを使用していて、タイマーが切れる前にコネクタが破棄された場合、どうすればよいですか。デストラクタでタイマーをキャンセルします。
- 自己結合