5

クライアントとサーバーにブロッキング TCP ソケットを使用しています。読むときはいつでも、最初に を使用してストリーム上でデータが利用可能かどうかを確認しますselect。私はいつも一度に 40 バイトを読み書きします。ほとんどの読み取りには数ミリ秒以下かかりますが、0.5 秒以上かかるものもあります。それは、ソケットで利用可能なデータがあることを知った後です。

私も使っていますTCP_NODELAY

何が原因ですか?

編集2

送受信された各パケットのタイムスタンプを分析したところ、この遅延は、サーバーによって次のオブジェクトが書き込まれる前にクライアントがオブジェクトを読み取ろうとした場合にのみ発生することがわかりました。たとえば、サーバーがオブジェクト番号 x を書き込んだ後、サーバーがオブジェクト番号 x+1 の書き込みを開始する前に、クライアントがオブジェクト x を読み取ろうとしました。これにより、サーバー側で何らかの合体が行われているのではないかと思われます。

編集

サーバーは 3 つの異なるポートでリッスンしています。クライアントは、これらの各ポートに 1 つずつ接続します。

3 つの接続があります。サーバーからクライアントにデータを頻繁に送信する接続です。クライアントからサーバーにデータを送信するだけの 2 つ目。そして、1バイトのデータを送信するためにめったに使用されない3番目のもの。最初の接続で問題に直面しています。その接続でデータが利用可能であることを確認しselect()てから、40 バイトの読み取りにタイムスタンプを付けると、その読み取りに約 0.5 秒かかったことがわかります。

これをプロファイリングする方法についての指針は非常に役立ちます

Linuxでgccを使用しています。

rdrr_server_start(void) {
int rr_sd; int input_sd; int ack_sd; int fp_sd;

startTcpServer(&rr_sd, remote_rr_port); startTcpServer(&input_sd, remote_input_port); startTcpServer(&ack_sd, remote_ack_port); startTcpServer(&fp_sd, remote_fp_port);

connFD_rr = getTcpConnection(rr_sd); connFD_input = getTcpConnection(input_sd); connFD_ack= getTcpConnection(ack_sd); connFD_fp=getTcpConnection(fp_sd); }

static int getTcpConnection(int sd) { socklen_t l en;
struct sockaddr_in clientAddress; len = sizeof(clientAddress); int connFD = accept(sd, (struct sockaddr*) &clientAddress, &len); nodelay(connFD); fflush(stdout); return connFD; }

static void startTcpServer(int *sd, const int port) { *sd= socket(AF_INET, SOCK_STREAM, 0); ASSERT(*sd>0);

// Set socket option so that port can be reused int enable = 1; setsockopt(*sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));

struct sockaddr_in a; memset(&a,0,sizeof(a)); a.sin_family = AF_INET; a.sin_port = port; a.sin_addr.s_addr = INADDR_ANY; int bindResult = bind(*sd, (struct sockaddr *) &a, sizeof(a)); ASSERT(bindResult ==0); listen(*sd,2); } static void nodelay(int fd) { int flag=1; ASSERT(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flag, sizeof flag)==0); }

startTcpClient() { connFD_rr = socket(AF_INET, SOCK_STREAM, 0); connFD_input = socket(AF_INET, SOCK_STREAM, 0); connFD_ack = socket(AF_INET, SOCK_STREAM, 0); connFD_fp= socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in a; memset(&a,0,sizeof(a)); a.sin_family = AF_INET; a.sin_port = remote_rr_port; a.sin_addr.s_addr = inet_addr(remote_server_ip);

int CONNECT_TO_SERVER= connect(connFD_rr, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_input_port; CONNECT_TO_SERVER= connect(connFD_input, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_ack_port; CONNECT_TO_SERVER= connect(connFD_ack, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_fp_port; CONNECT_TO_SERVER= connect(connFD_fp, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

nodelay(connFD_rr); nodelay(connFD_input); nodelay(connFD_ack); nodelay(connFD_fp); }

4

5 に答える 5

1

私はこのコード行を疑っています:

ASSERT(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flag, sizeof flag)==0);  

リリース ビルドを実行している場合、ASSERT はほとんど何も定義されていない可能性が高いため、呼び出しは実際には行われません。setsockopt 呼び出しを ASSERT ステートメントに含めないでください。代わりに、(変数内の) 戻り値を assert ステートメントで検証する必要があります。 副作用のあるアサートは一般的に悪いことです。したがって、これが問題でなくても、おそらく変更する必要があります。

于 2012-05-25T14:06:09.747 に答える
0

あなたの声明はまだ混乱しています。つまり、「1つのクライアントのみとの複数のtcp接続」です。明らかに、1 つのポートでリッスンしている単一のサーバーがあります。複数の接続がある場合、これは、サーバーに接続している複数のクライアントがあり、それぞれが異なる tcp クライアント ポートに接続されていることを意味します。これで、サーバーは select を実行し、データを持っているクライアントに応答します (クライアントがソケットでデータを送信したことを意味します)。2 つのクライアントが同時にデータを送信した場合、サーバーはそれらを順番にしか処理できません。したがって、サーバーが最初のクライアントの処理を完了するまで、2 番目のクライアントは処理されません。

Select は、サーバーが複数の記述子 (ソケット) を監視し、利用可能なデータがあるものを処理することのみを許可します。並行して処理を行うようなものではありません。そのためには、複数のスレッドまたはプロセスが必要です。

于 2012-05-25T10:52:18.527 に答える
0

1 つのクライアントと複数の接続?

一部のソケット関数が実行をブロックしている (つまり、関数の結果を待っている) 可能性があります。相互に干渉しないように、接続ごとに(サーバー側で)新しいスレッドを開くことをお勧めします...

しかし、私は暗闇の中で撮影しています。追加情報を送信する必要があります...

于 2012-05-25T10:30:01.107 に答える
0

多分それはtimeout議論に関連するものです。

callのtimeout引数には何を設定しますか?select

タイムアウト引数をより大きなものに変更して、待ち時間を観察してみてください。タイムアウトが小さすぎる場合や、システム コールが実際にスループットを低下させることがよくあります。もう少し大きなレイテンシーを想定すれば、より良い結果が得られるかもしれませんが、それは実現可能です。

タイムアウトまたはコードのバグが疑われます。

于 2012-05-25T11:23:08.097 に答える