10

TCP プロトコルを使用して単純なクライアント サーバー アプリケーションを作成しています。

私はデフォルトでそれを知っています。反対側がこのソケットにrecv()a を呼び出すまでブロックします。send()しかし、送信キューに ing を保持するのではなく、反対側がメッセージを編集するsend()までそれ自体をブロックし、後で反対側が複数の sによって送信された大量のメッセージを取得したことを確認することは可能ですか?recv()send()recv()send()

言い換えると。別の側を呼び出す前に、すべてsend()の側を待機させることは可能ですか?recv()send()

私の質問を説明するために。ここに簡単なコードを投稿します。

client.c

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <poll.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h> 

int main(int argc, char *argv[])
{
    int sockfd = 0;
    char sendBuff[1024];
    struct sockaddr_in serv_addr;
    int i;

    if(argc != 2)
    {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    } 

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    } 

    memset(&serv_addr, '0', sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000); 

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    } 

    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("\n Error : Connect Failed \n");
        return 1;
    }

    do{
        memset(sendBuff, '\0', sizeof(sendBuff));
        sprintf(sendBuff, "This is line %d", i);
        send(sockfd, sendBuff, strlen(sendBuff), 0);
        //sleep(1);
    }while(++i<100);

    return 0;
}

server.c

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

int main(int argc, char *argv[])
{
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr; 

    char sendBuff[1025];
    char recvBuff[100];

    int i = 0;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

    listen(listenfd, 10); 

    connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

    do{  
        memset(recvBuff, '\0', sizeof(recvBuff));
        recv(connfd, recvBuff, sizeof(recvBuff),0);
        printf( "%s\n", recvBuff);
    }while(++i<100); 

    return 0;
} 

サーバー側の結果に期待するのは、次のように出力することです。

This is line 0
This is line 1
This is line 2
This is line 3
...

ただし、実際の結果は次のようになります。

This is line 0
This is line 1This is line 2This is line3This is line 4
This is line 5This is line 6This is line 7This is line 8This is line 9This is line 10
This is line 11This is line 12...

ただし、これは簡単に説明できます。クライアント側が を発行したときにsend()、サーバー側が終了するのを待たず、recv()何らかの理由で、サーバー側のrecv()ループがクライアント側の よりも遅くなりますsend()。したがってsend()、クライアント側のいくつかの が一緒に積み上げられ、サーバー全体で受信される場合があります。(私の説明は正しいですか?)

実際、非常にばかげた緩い解決策があるようです。ループ内のsleep(1)各後に(コメントアウトしたように)を追加するだけです。send()これによりコードが非常に非効率的になり、recv()ループが他の複雑なアクションを実装するのに時間がかかる場合(プログラムが大きくなると、これは明らかに予測できません)、1秒以上かかることはわかっています。このソリューションは失敗します。

では、2 つの側が相互に通信して、1 つのシングルによって送信されたメッセージが 1 つのシングルsend()によって受信されることを保証する、より確実な方法はありrecv()ますか?

4

3 に答える 3

8

client.c

while(condition)
{
  send() from client;
  recv() from server;
}

server.c

recv() from client;
while(condition)
{
  send() from server; //acknowledge to client
  recv() from client;
}
于 2013-11-05T17:46:28.967 に答える
2

問題が一度に 1 つのメッセージを処理するだけの場合は、長さフィールドを含めてみませんか? 送信者

int sendLen = strlen(sendBuff);
send(sockfd, &sendLen, sizeof(sendLen), 0);
send(sockfd, sendBuff, sendLen, 0);

レシーバー

int len = 0;
recv(connfd, &len, sizeof(len), 0);
recv(connfd, recvBuff, len, 0);

これにより、一度に 1 つのメッセージを読み取り、残りを tcp バッファーに残すことができます。

上記のコードは、エンディアンと int サイズを共有する送信プログラムと受信プログラムについて多くの仮定を置いていることに注意してください。(すべてが1台のマシンで実行されている場合は問題ありません)また、エラーの戻りをチェックせず、エラーの可能性がありますsend()recv()

于 2013-11-05T18:10:43.950 に答える