Shammer's Philosophy

My private adversaria

EchoClientV2

以下の記事等でいろいろやってきたが、原因はケアレスミスだった。

Receive message の直後、

receiveMsgSize = recv(sock, echo_buffer, sizeof(echo_buffer) - 1, 0);

とあるが、sizeof の後の - 1 を削除したらうまくいった。
これを削除したのは、http://www.amazon.co.jp/TCP-IPソケットプログラミング-C言語編-Michael-Donahoo/dp/4274065197の35ページの実装を見習ったのだが、この - 1 の理由をしっかり把握できていなかった。37ページの解説にはこうある。

recv()は、データが利用可能になるまでプログラムの実行をブロックします。データ受信後に、バッファにコピーしたバイト数を返すか、エラー時に-1を返します。(略)なお、recv()に渡されるサイズを示すパラメータには、文字列の終わりを表すNULL文字を加えたバイトデータのサイズが指定されます。このNULL文字によって、printf()では文字列の末尾を確認できます。

ややこしい書き方をしているが、この本ではprintfの前に\0を付与してからprintfしている。なぜ -1 しているかについても説明があるが、それはサンプルの仕様のためらしい。通常はそのまま受け取った文字列を printf してよさそうだ。最終実装は以下のとおり。

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int error_exit(char *message) {
    perror(message);
    exit(1);
}

int checknumber(char *v){
    int len = strlen(v);
    int i;
    int result = 1;
    for(i = 0; i < len && result ; i++){
	result = isdigit(v[i]);
    }
    return result;
}

int main(int argc, char *args[]){
    if( argc != 3 && argc != 4 ) {
	printf("Usage: %s $ListenAddress $ListenPort $EchoMessage\n", args[0]);
	printf("       %s $ListenAddress $EchoMessage\n", args[0]);
    }
    else {
	if( checknumber(args[2]) != 1 ){
	    printf("%s is not number, the 2nd arguments has to be a number.\n", args[2]);
	}
	else {
	    int sock;
	    struct sockaddr_in destination_addr;
	    unsigned short destination_port;
	    char echo_buffer[256];
	    unsigned int message_length;
	    int receivedbytes, totalreceivedbyte;
	    if( argc == 3 ){
		destination_port = 7;
	    }
	    else if( argc == 4 ){
		destination_port = atoi(args[2]);
	    }
	    // Socket open, this is a 1st step.
	    if( (sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ){
		error_exit("socket() failed.\n");
	    }
	    // Build Destination Socket Informations
	    memset(&destination_addr, 0, sizeof(destination_addr));
	    destination_addr.sin_family = AF_INET;
	    destination_addr.sin_addr.s_addr = inet_addr(args[1]);
	    //destination_addr.sin_port = destination_port;
	    destination_addr.sin_port = htons(destination_port);
	    if( connect(sock, (struct sockaddr *)&destination_addr, sizeof(destination_addr)) < 0 ){
		error_exit("connect() failed.\n");
	    }
	    // Check echo message length
	    message_length = strlen(args[3]);
	    // Send message
	    if( send(sock, args[3], message_length, 0) != message_length ){
		error_exit("send() finished uncompletely...\n");
	    }

	    // Receive message
	    int receiveMsgSize = 0;
    	    receiveMsgSize = recv(sock, echo_buffer, sizeof(echo_buffer), 0);
	    if( receiveMsgSize < 0 ){
		error_exit("recv failed...\n");
	    }
	    else {
		printf("Received Message:%s\n", echo_buffer);
	    }

	    close(sock);
	    
	}
    }
    return 0;
}