EchoClientV2
以下の記事等でいろいろやってきたが、原因はケアレスミスだった。
- EchoClientV2_apha - Shammerism
- EchoClientV2_Debug - Shammerism
- warning: incompatible integer to pointer conversion assigning to 'char *' from 'int' [-Wint-conversion] - Shammerism
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; }