インターネット経由で postgreSQL データベースにクエリを実行する C++ クライアント プログラムを作成しています。応答を待っている間にネットワーク接続の問題が発生し、クライアントがデータベース サーバーからメッセージを受信できない場合に、イベントを処理したいと考えています。しかし、インターネット接続を手動でオフにすると、後で接続をオンにしても、プログラムはアイドル状態のままになります。このイベントをキャッチする方法、または少なくともクライアント側でタイムアウトを設定して、その後の応答の待機を停止する方法はありますか?
質問する
1279 次
2 に答える
3
timeval
構造体と への呼び出しを使用して、任意のソケット操作 (接続とは異なる) のタイムアウトを設定できますsetsockopt
。
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if ( setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
error( "setsockopt failed\n");
SO_RCVTIMEO
オプションは、入力操作を示すために使用されます。
select
タイムアウト パラメータを使用して、非ブロッキング ソケットを呼び出すこともできます。
const int timeout_msecs = 5000;
struct timeval tval;
tval.tv_usec = 1000 * (timeout_msecs % 1000);
tval.tv_sec = timeout_msecs / 1000;
fd_set waitSet;
FD_ZERO( &waitSet );
FD_SET( fd, &waitSet );
int ret;
ret = select( fd + 1, &waitSet, NULL, NULL, &tval );
最後に、リチャード・スティーブンスが彼の「Unix Networking Programming」で示したテクニックには、システム割り込みの使用が含まれます。
static void
sig_alrm(int signo)
{
return; /* just interrupt the recvfrom() */
}
void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
Signal(SIGALRM, sig_alrm);
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
alarm(5);
// call recvfrom with 5 seconds timeout
if ( (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
if (errno == EINTR)
fprintf(stderr, "socket timeout\n");
else
err_sys("recvfrom error");
} else {
alarm(0);
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
}
于 2014-05-06T10:37:28.667 に答える
0
ソケット操作を使用するためのプライベート データ パブリック チャネル 2 の提案に従って検索した後、次の解決策にたどり着きました。
pqxx::connection conn("host=blabla.com "
"port=5432 "
"user=abla "
"password=abla "
"dbname=ablabla");
const int val1 = 1;
if ( setsockopt(conn.sock(), SOL_SOCKET, SO_KEEPALIVE, &val1, sizeof(val1)) < 0){
perror( "setsockopt failed\n");
}
const int val2 = 5;
if ( setsockopt(conn.sock(), IPPROTO_TCP, TCP_KEEPCNT, &val2, sizeof(val2)) < 0){
perror( "setsockopt failed\n");
}
const int val3 = 2;
if ( setsockopt(conn.sock(), IPPROTO_TCP, TCP_KEEPINTVL, &val3, sizeof(val3)) < 0){
perror( "setsockopt failed\n");
}
const int val4 = 10;
if ( setsockopt(conn.sock(), IPPROTO_TCP, TCP_KEEPIDLE, &val4, sizeof(val4)) < 0){
perror( "setsockopt failed\n");
}
TransactorImpl transac();
conn.perform(transac,10);
このようにして、ネットワークから切断してから 10 秒後に、ソケットがプローブの送信を開始して接続が正常であることを確認し、しばらくすると接続が中止され、オーバーライドさon_abort()
れた関数が呼び出され、その後 libpqxx がクエリの実行を再試行します。再試行の回数は、perform()
関数の 2 番目の引数 (この場合は 10) によって指定されます。
于 2014-05-06T14:37:54.293 に答える