2009-07-11 8 views
2

Cを使用してサーバーアプリケーションに文字列を送信しようとしていますが、私はかなりネットワークプログラミングに新しいです、私は自分のコードが間違ったツリーを吠えていると思います。バッファの長さとバッファのソケット上での送信

メッセージは、メッセージの長さ+メッセージであるとすると、(生着信データであるbufを)などのPythonのサーバによって反対側に展開される:

msg_len_bytes = buf[0:4] 
msg_len = struct.unpack("!L", msg_len_bytes)[0] 

!ネットワークのバイトオーダーを意味し、Lは符号なしlongを意味します。

通常の文字列を送信するのはかなり簡単です。 send(sock、message、strlen(message)、0);

しかし、メッセージの長さを追加すると、私はかなりハンドルを得ることができません。ここでは、これまでに私のクライアントのためのコードです:

struct msgstruct { 
     uint32_t length; 
     char send_data[4096]; 
}; 

int main() 

{ 
    int sock; 
    struct msgstruct message; 
    char data[4096] = "<MOP><test/></MOP>"; 

    for (int i = 0; i < strlen(data); i++) { 
     message.send_data[i] = data[1]; 
    } 

    struct hostent *host; 
    struct sockaddr_in server_addr; 

    unsigned long buflen = sizeof(message.send_data); 
    uint32_t bufsend = htonl(buflen); 

    message.length = bufsend; 

    host = gethostbyname("127.0.0.1"); 

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 
     perror("Socket"); 
     exit(1); 
    } 

    server_addr.sin_family = AF_INET;  
    server_addr.sin_port = htons(12998); 
    server_addr.sin_addr = *((struct in_addr *)host->h_addr); 
    bzero(&(server_addr.sin_zero),8); 


    if (connect(sock, (struct sockaddr *)&server_addr, 
       sizeof(struct sockaddr)) == -1) { 
     perror("Connect"); 
     exit(1); 
    } 

    if(send(sock, message.length + message.send_data, sizeof(message), 0) == -1){ 
     printf("\nSocket error."); 
     exit(1); 
    } 
    return 0; 
} 

私はいくつかのバリエーションを試してみたが、私は常にソケットエラーで終わります。それは送信のための2番目の引数で型を混合しているからですか?私は構造体を送信しようとするとコンパイルエラーが発生します。

+1

あなたが提供する答えに満足している場合は、チェックマークと「正解」として(私の願わくば!)ものを選択してください。それは15の報酬の価値がある。私のことを指摘し、今後の参考文献でこの質問をより有効にしています。 – abelenky

答えて

4

エラーは、このコードである:送信用

send(sock, message.length + message.send_data, sizeof(message), 0) 

プロトタイプは:パラメータ2がポインタであることを

ssize_t send(int s, const void *buf, size_t len, int flags); 

注意。 コードでは、長さ(Type uint32_t)をバッファ(Type char *)に追加しています。 このように追加すると、char *、(ポインタへのポインタ)が返されますが、予測できない無意味なメモリ領域へのポインタになります。

は、バッファへのポインタを取得するには、希望:構造体のアドレスを取得することにより、パディングの問題のために、ポータブルまたは常に賢明ではないことを

send(sock, &message, sizeof(message), 0) 

注意を。しかし、典型的な32ビットアーキテクチャでは、これはうまくいくはずです。

これは、メッセージ構造体から開始して4100(4096 + 4)バイトを送信するデータを送信します。 私はそれをあまり送るつもりはないと思います。 3番目のパラメータは、バイトを送信するためにどのように多くの言う、とに設定する必要があります。これはがNULL終止符データについては含まれていませないことが、forループ、あなたの初期にはなかったことを

sizeof(uint32_t) + strlen(data); // 4-byte Integer + Length of the data "<MOP><test/></MOP>" 

注意(あなたはNULL終止符をしたい場合は、forループ初期はのstrlen(データ)+1に移動し、他の場所でのstrlen(データ)+1を使用して作るのいずれかNULL終止符をコピー

同じように)。

理想的には、strlen(データ)をローカル変数にキャッシュし、あまりそれを呼び出さないようにしてください。 (inital for-loopでstrlenを繰り返し呼び出すこともできます)。

あなたの最後の文は次のようになります。

if(send(sock, &message, sizeof(uint32_t)+strlen(data), 0) == -1){ 
    printf("\nSocket error."); 
    exit(1); 
} 

はそれを試してみてください、と私はそれが行く方法を知ってみましょう。

+0

ええと、私はそれをすると、サーバーに大量のごみが送られているように思えます。 –

+0

くつろぎの言葉も同様です。あなたはデータ[i]を持つべきデータ[1]を持っています! – abelenky

+0

申し訳ありませんが、間違った投稿にコメントしました –

0

messageインスタンスにコピーデータが破壊されるループは、それがiを有するべきである1有します。

send()の2番目の引数は、送信する最初のバイトへのポインタにする必要があります。代わりに、ビッグエンディアンの数字(あなたのプラットフォームがビッグエンディアンでない場合、非常に間違っています)とランダムな配列ベースアドレスの合計を与えます。これは間違っています。

あなたが必要:

if(send(sock, &message, sizeof message.length + strlen(data), 0) == -1) { 

他のいくつかの混乱もあり、あなたは常にではなく、必要なだけの量よりも、フル4Kを送信するために、「欲しい」ように見えます。あなたが使用することができます

5

2以降の送信:

send(sock, &message.length, sizeof(message.length), 0); 
send(sock, message.send_data, message.length*sizeof(char), 0); 

それとも、より良いメッセージの長さとして最初の4バイトでバッファを準備します

char buff[MAX_BUFF] = ""; 
int len_disp = sizeof(message.length); 
memcpy(buff, &message.length, len_disp); 
memcpy(&buff[len_disp], &message.length, message.length*sizeof(char)); 
send(sock, buff, message.length*sizeof(char) + len_disp, 0); 

はEDIT:小さなメッセージについては がコメント - Nagleアルゴリズムを無効にします。

BOOL bNagleEnabled = FALSE; 
if(setsockopt(sAccept, IPPROTO_TCP, TCP_NODELAY, (char *)&bNagleEnabled, sizeof(BOOL))) 
{ 
    ReportError("Setting TCP_NODELAY socket option failed"); 
    return -2; 
} 
+1

+1と長さとデータを別々のセンドで使用します。これは、コンパイラが長さとバッファの間にデータを挿入するように感じる場合に特に重要です。 –

+0

これを行うライブラリはありませんか?そうでなければ、私はサイズヘッダとして可変長の数量を除いて1つを作っています... – sudo

0

基本的には、すべてバッファを入れてソケットで送受信する必要があります。 ので、通常私は何をすべきか:

//Send 
memcpy(buffer, &structure_u_defined, sizeof(structure_u_defined)); 
send(&sock, buffer,...);// lol I am using a public pc 

//receive 
recv(&sock, buffer,...); 
memcpy(&structure_u_defined_for_receive, buffer, sizeof(buffer)); 
関連する問題