dポイントプレゼントキャンペーン実施中!

タイトル通りです。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. …

A 回答 (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アドレス&ポート番号が関係づけられるはずです。
    • good
    • 0
この回答へのお礼

大変ありがとうございます!
お陰様で解決しました。
仰った通りに例の部分を移動しましたら
こんな風に表示されました:

クライアント側
(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()が成功した後に使うべきなんですね。
勉強になりました。ずーっと悩んでいたんで助かりました。
質問してよかったです。
本当にありがとうございました!

お礼日時:2006/04/02 09:51

>if (getsockname(sock, (struct sockaddr *)&sin, &len) < 0){


>error("getsockname failed.\n");
>}

の error が未定義です。
これを 
DieWithError("getsockname failed.\n");
に変えてください。
    • good
    • 0
この回答へのお礼

ありがとうございます!
はい、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 …

Example code from the text
の下の
TCPEchoServer-Fork.c (without SIGCHLD)です。
※コンパイルエラーを解決してくださったので
どちらにしてもポイントを差し上げます。

お礼日時:2006/04/02 06:07

sockは、socket() で作成したディスクリプター(descriptor)の筈なので間違いないと思います。



コンパイラから出てるメッセージが
>Undefined first referenced symbol in file

って事で、externとかでDieWithError()を宣言するか
1ファイルにまとめたら案外解決しそうな気がします・・・。
    • good
    • 0
この回答へのお礼

ありがとうございます。
#3さんのお礼にも書きましたがコンパイルエラーは解決しました。
しかし、肝心の正しいIPアドレスとポート番号はまだ得られていません。
何かお気付きの点はありますか?

お礼日時:2006/04/02 06:09

ソースは、2つコンパイルかけてるんですか?


>gcc -o tcpc TCPEchoClient.c dwe.c

makefile作ってコンパイルとリンク分けた方がいいですよ。
まず、どのファイルがエラーになってるか判らない気がします。

この回答への補足

ありがとうございます(と補足に書いてしまいます)。
はい、二つコンパイルかけてます。
でも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 …
の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");
//↓続く

補足日時:2006/04/01 12:12
    • good
    • 0
この回答へのお礼

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);
}

お礼日時:2006/04/01 12:37

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!