- ベストアンサー
TCP/IPでのgetsockname()の使い方を教えてください
タイトル通りです。UNIX Solarisで環境はgccです。 クライアント側でクライアント自身のIPアドレスとポート番号が知りたいのですが getsockname()を使うと意味不明のエラーが出ます: (xxxxx) gcc -o tcpc TCPEchoClient.c dwe.c -lsocket -lnsl Undefined first referenced symbol in file error /var/tmp//ccQLXX4R.o ld: fatal: Symbol referencing errors. No output written to tcpc collect2: ld returned 1 exit status 以下が関連しているだろう部分の抜粋です。 if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); struct sockaddr_in sin; int len; // u_long local_ip; unsigned long local_ip; len = sizeof(sin); if (getsockname(sock, (struct sockaddr *)&sin, &len) < 0){ error("getsockname failed.\n"); } local_ip = ntohl(sin.sin_addr.s_addr); printf("PORT %d,%d,%d,%d,%d,%d\n", (int)(local_ip >> 24) & 0xff, (int)(local_ip >> 16) & 0xff, (int)(local_ip >> 8) & 0xff, (int)(local_ip) & 0xff, (ntohs(echoServAddr.sin_port) >> 8) & 0xff, ntohs(echoServAddr.sin_port) & 0xff); どこがおかしいか判りますか? 必要であれば全体のコードも補足します(そんなに長くないです)。 ちなみにここ↓を参考にしました。 http://www.coins.tsukuba.ac.jp/~syspro/2005/No8.html
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>どこか怪しいところはありますか? >if (getsockname(sock, (struct sockaddr *)&sin, &len) < 0){//←sockでいいですか? error("getsockname failed.\n"); } >local_ip = ntohl(sin.sin_addr.s_addr); >printf("PORT %d,%d,%d,%d,%d,%d\n", >(int)(local_ip >> 24) & 0xff, >(int)(local_ip >> 16) & 0xff, >(int)(local_ip >> 8) & 0xff, >(int)(local_ip) & 0xff, >(ntohs(echoServAddr.sin_port) >> 8) & 0xff, >ntohs(echoServAddr.sin_port) & 0xff); この部分を if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) DieWithError("connect() failed"); の後に移動してください。 connectが成功して初めて、ソケットとIPアドレス&ポート番号が関係づけられるはずです。
その他の回答 (3)
- tatsu99
- ベストアンサー率52% (391/751)
>if (getsockname(sock, (struct sockaddr *)&sin, &len) < 0){ >error("getsockname failed.\n"); >} の error が未定義です。 これを DieWithError("getsockname failed.\n"); に変えてください。
お礼
ありがとうございます! はい、DieWithError("getsockname failed.\n");に変えたらコンパイルできました! しかし、返ってきたポート番号が以下のようになりました。 (mort) tcpc 127.0.0.1 "Echo!" 29995 PORT 255,255,255,255,0,0 Received: Echo! 255なんて出るので何か読んでるのは確かでしょうけど サーバーのaccept()が読んだクライアントの情報によると (mort) tcps 29995 Handling client: IP address = 127.0.0.1 Handling client: Port Number = 40069 with child process: 20911 です。どこか怪しいところはありますか? ちゃんと読まれているか調べる方法はないものでしょうか? ちなみにサーバーは例によって http://books.elsevier.com/us//mk/us/subindex.asp?maintarget=companions/defaultindividual.asp&isbn=1558608265&country=United+States&srccode=&ref=&subcode=&head=&pdf=&basiccode=&txtSearch=&SearchField=&operator=&order=&community=mk の Example code from the text の下の TCPEchoServer-Fork.c (without SIGCHLD)です。 ※コンパイルエラーを解決してくださったので どちらにしてもポイントを差し上げます。
- t_nojiri
- ベストアンサー率28% (595/2071)
sockは、socket() で作成したディスクリプター(descriptor)の筈なので間違いないと思います。 コンパイラから出てるメッセージが >Undefined first referenced symbol in file って事で、externとかでDieWithError()を宣言するか 1ファイルにまとめたら案外解決しそうな気がします・・・。
お礼
ありがとうございます。 #3さんのお礼にも書きましたがコンパイルエラーは解決しました。 しかし、肝心の正しいIPアドレスとポート番号はまだ得られていません。 何かお気付きの点はありますか?
- t_nojiri
- ベストアンサー率28% (595/2071)
ソースは、2つコンパイルかけてるんですか? >gcc -o tcpc TCPEchoClient.c dwe.c makefile作ってコンパイルとリンク分けた方がいいですよ。 まず、どのファイルがエラーになってるか判らない気がします。
お礼
struct sockaddr_in sin; int len; unsigned long local_ip; len = sizeof(sin); if (getsockname(sock, (struct sockaddr *)&sin, &len) < 0){//←sockでいいですか? error("getsockname failed.\n"); } local_ip = ntohl(sin.sin_addr.s_addr); printf("PORT %d,%d,%d,%d,%d,%d\n", (int)(local_ip >> 24) & 0xff, (int)(local_ip >> 16) & 0xff, (int)(local_ip >> 8) & 0xff, (int)(local_ip) & 0xff, (ntohs(echoServAddr.sin_port) >> 8) & 0xff, ntohs(echoServAddr.sin_port) & 0xff); memset(&echoServAddr, 0, sizeof(echoServAddr)); echoServAddr.sin_family = AF_INET; echoServAddr.sin_addr.s_addr = inet_addr(servIP); echoServAddr.sin_port = htons(echoServPort); if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) DieWithError("connect() failed"); echoStringLen = strlen(echoString); if (send(sock, echoString, echoStringLen, 0) != echoStringLen) DieWithError("send() sent a different number of bytes than expected"); totalBytesRcvd = 0; printf("Received: "); while (totalBytesRcvd < echoStringLen) { if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0) DieWithError("recv() failed or connection closed prematurely"); totalBytesRcvd += bytesRcvd; echoBuffer[bytesRcvd] = '\0'; printf(echoBuffer); } printf("\n"); close(sock); exit(0); }
補足
ありがとうございます(と補足に書いてしまいます)。 はい、二つコンパイルかけてます。 でもdwe.cにエラーがある可能性は0です。なんてったって #include <stdio.h> /* for perror() */ #include <stdlib.h> /* for exit() */ void DieWithError(char *errorMessage){ perror(errorMessage); exit(1); } //だけですから。(笑) では、全体のコードを。 元のコードは http://books.elsevier.com/us//mk/us/subindex.asp?maintarget=companions/defaultindividual.asp&isbn=1558608265&country=United+States&srccode=&ref=&subcode=&head=&pdf=&basiccode=&txtSearch=&SearchField=&operator=&order=&community=mk のTCPEchoClient.cです。 #include <stdio.h> /* for printf() and fprintf() */ #include <sys/socket.h> /* for socket(), connect(), send(), and recv() */ #include <arpa/inet.h> /* for sockaddr_in and inet_addr() */ #include <stdlib.h> /* for atoi() and exit() */ #include <string.h> /* for memset() */ #include <unistd.h> /* for close() */ #define RCVBUFSIZE 32 /* Size of receive buffer */ void DieWithError(char *errorMessage); /* Error handling function */ int main(int argc, char *argv[]) { int sock; /* Socket descriptor */ struct sockaddr_in echoServAddr; /* Echo server address */ unsigned short echoServPort; /* Echo server port */ char *servIP; /* Server IP address (dotted quad) */ char *echoString; /* String to send to echo server */ char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */ unsigned int echoStringLen; /* Length of string to echo */ int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv() and total bytes read */ if ((argc < 3) || (argc > 4)) /* Test for correct number of arguments */ { fprintf(stderr, "Usage: %s <Server IP> <Echo Word> [<Echo Port>]\n", argv[0]); exit(1); } servIP = argv[1]; /* First arg: server IP address (dotted quad) */ echoString = argv[2]; /* Second arg: string to echo */ if (argc == 4) echoServPort = atoi(argv[3]); /* Use given port, if any */ else echoServPort = 7; /* 7 is the well-known port for the echo service */ /* Create a reliable, stream socket using TCP */ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); //↓続く
お礼
大変ありがとうございます! お陰様で解決しました。 仰った通りに例の部分を移動しましたら こんな風に表示されました: クライアント側 (lefanu) tcpc 127.0.0.1 "Echo!" 29995 PORT 127,0,0,1,157,196 Received: Echo! サーバー側 Handling client: IP address = 127.0.0.1 Handling client: Port Number = 40388 with child process: 27895 で、IPアドレスは正しいとして ポート番号が157,196 (!?)と思っていたんですが コードを読むと8ビットのシフトがされており Calcで二進数に直して合わせてみると見事、 157 = 10011101 196 = 11000100 1001110111000100 = 40388 (!) となりました。ですから printf("PORT %d,%d,%d,%d,%d\n", (int)(local_ip >> 24) & 0xff, (int)(local_ip >> 16) & 0xff, (int)(local_ip >> 8) & 0xff, (int)(local_ip) & 0xff, ntohs(sin.sin_port)); //←変更部分 と書き替えました。 なるほど、getsockname()はconnect()が成功した後に使うべきなんですね。 勉強になりました。ずーっと悩んでいたんで助かりました。 質問してよかったです。 本当にありがとうございました!