1

TCPで基本的なクライアントとサーバーを構築しています。キーが少し大きくなる場合を除いて、機能しています。時間の終わりまでキーを前後に送信するだけです。大きくなると(別名4096)、read()ステートメントはランダムにnullを取得し、キーを2つのmsgに分割して、サイクルを中断します。

なぜこれが行われているのかよくわかりません。サーバーコードは他のクライアントでテストされているため機能しているため、クライアントに問題があります。任意のアイデア(かなり短いです):

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

#define BUFFER_LENGTH 5120

// Error message taken from reference
void error(const char *msg)
{
    printf("%s\n", msg);
    exit(0);
}
int main(int argc, char *argv[])
{
    int sockfd, portNumber, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    // Invalid arguments
    if (argc < 4)
        exit(0);
    else if (atoi(argv[3]) < 1 || atoi(argv[3]) > 4096)
        exit(0);

    char buffer[BUFFER_LENGTH];
    bzero(buffer, BUFFER_LENGTH);
    char buffer2[BUFFER_LENGTH];
    bzero(buffer2, BUFFER_LENGTH);
    strcpy(buffer2, "Connect.  Key length:  ");
    strcpy(buffer, strcat(buffer2, argv[3]));
    portNumber = atoi(argv[2]); // Get port number in int format
    sockfd = socket(AF_INET, SOCK_STREAM, 0); // Create socket connection to server using internet constants

    // Did we open the socket succesfully?
    if (sockfd < 0)
        error("Error opening socket.");

    // Is the IP Address valid?
    server = gethostbyname(argv[1]);
    if (server == NULL)
        error("Could not connect to server. Terminating.");

    // Initialize to zero and then set
    // Taken from reference
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portNumber);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("Could not connect to server. Terminating.");

    short connected = 1;
    do 
    {
        // Send initial request on first pass
        // Afterwards send the resposne we were given
        printf("Sending: %s\n", buffer);
        printf("Length of msg: %d\n", (strlen(buffer) + 1));
        n = write(sockfd, buffer, strlen(buffer) + 1);
        if (n < 1) 
             error("Failed to send Message. Terminating.");

        // Get session key response
        bzero(buffer, BUFFER_LENGTH);
        n = read(sockfd, buffer, BUFFER_LENGTH);
        if (n < 1)
            error("Could not fetch result.  Terminating.");

        // Stop
        if (strcmp(buffer, "Invalid session key.  Terminating.") == 0)
            break;

        printf("%s\n", buffer);
        sleep(1);
    } while (connected == 1);

    // Done (this should never be reached in this client)
    error("Could not fetch result.  Terminating.");
    close(sockfd);
    return 0;
}
4

3 に答える 3

5

バイナリデータではstrcpy()、または関数を使用しないでください。str*()あなたは文字列を扱っていません。コピーするバイト数を使用memcpy()して指定します。

str*()関数は文字列を操作します; 文字列は、C標準では、「最初のヌル文字で終了し、それを含む連続した文字シーケンス」として定義されています。ただし、バイナリデータでは、ヌル文字(ゼロバイト)は、必ずしも意味を持たないデータの別のチャンクです。

バイナリデータが次のようになっている場合(16進数):

4b d9 e7 b3 00 96 89 fb

その後、バイトstrcpy()以降のすべてを無視します。00さらに悪いことに、バイナリデータが次のようになっている場合:

4b d9 e7 b3 2f 96 89 fb

nullバイトがないstrcpy()場合、、、、またはstrlen()、または任意の文字列関数はバッファの終わりを超えて続行し、予測できない結果になります。

于 2012-10-14T22:32:53.207 に答える
1

あなたは、1人が送信したデータが1人write()だけによって読み取られると想定していますread()。TCPまたはSocketsAPI仕様には、この仮定をサポートするものはありません。メッセージ全体が表示されるまで読む必要があります。「メッセージ」は、TCPやAPIではなく、ユーザーが定義します。

于 2012-10-15T01:06:11.523 に答える
-1

デバッグの目的でのみ、サーバーが応答する時間を与えるために、とsleep()の間でおそらく役立つでしょうか?適切なタイムアウトを構成することは、長期的にそれを処理するための正しい方法です。それからまた、私は完全に間違った方向に進んでいる可能性があります。write()read()

于 2012-10-14T22:30:12.013 に答える