http://ash.jp/net/prog_net.htm
上記のWebページに掲載されているC言語版の"hellosv.c","hellocl.c","makefile"を同一のディレクトリ下にダウンロードし、"make all"を実行したところ以下のようなエラーが発生し上手くコンパイルすることができません。
cc -o hellosv hellosv.c -lsocket -lnsl -dn
cc1: 警告: 認識できない gcc デバッグオプション: n
hellosv.c: In function ‘main’:
hellosv.c:45: 警告: incompatible implicit declaration of built-in function ‘bzero’
hellosv.c:48: 警告: incompatible implicit declaration of built-in function ‘memcpy’
hellosv.c:50: 警告: passing argument 2 of ‘bind’ from incompatible pointer type
/usr/include/sys/socket.h:115: note: expected ‘const struct sockaddr *’ but argument is of type ‘struct sockaddr_in *’
hellosv.c:66: 警告: passing argument 2 of ‘accept’ from incompatible pointer type
/usr/include/sys/socket.h:214: note: expected ‘struct sockaddr * __restrict__’ but argument is of type ‘struct sockaddr_in *’
hellosv.c:85: 警告: incompatible implicit declaration of built-in function ‘exit’
/usr/bin/ld: cannot find -lsocket
collect2: ld はステータス 1 で終了しました
make: *** [hellosv] エラー 1
解決方法をご教示いただけないでしょうか?
本気で勉強するなら、以下を薦めておきます。
UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI
とりあえず修正してみました。FreeBSDとdebian で動いています。
% cc -Wall -o hellosv hellosv.c % cc -Wall -o hellosv hellocl.c %
/* */ /* コネクション型のサーバプログラム (hellosv.c) */ /* Usage: hellosv host_name & */ /* */ #include <stdio.h> #include <netdb.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define PROT_NO 5001 static char mesg[] = "Hello world."; static struct sockaddr_in sv_addr; /* サーバアドレス */ static struct sockaddr_in cl_addr; /* クライアントアドレス */ static struct hostent *sv_ip; /* サーバIPアドレス */ static int sid1; /* デーモンソケット識別子 */ static int sid2; /* 子プロセスソケット識別子 */ static int cl_size; /* クライアントアドレスサイズ */ /* サーバメイン */ int main(argc, argv) int argc; char *argv[]; /* argv[1]:サーバホスト名 */ { int rtn; /* 返却値 */ /* コネクション型ソケットの作成 (socket) */ sid1 = socket(AF_INET, SOCK_STREAM, 0); if (sid1 < 0) { perror("sv:socket"); goto err; } /* サーバのIPアドレスを取得 */ sv_ip = gethostbyname(argv[1]); if (sv_ip == NULL) { perror("sv:gethostbyname"); goto err; } /* ソケットに名前を付加 (bind) */ bzero((char *)&sv_addr, sizeof(sv_addr)); sv_addr.sin_family = AF_INET; sv_addr.sin_port = htons(PROT_NO); memcpy((char *)&sv_addr.sin_addr, (char *)sv_ip->h_addr, sv_ip->h_length); rtn = bind(sid1, (struct sockaddr *)&sv_addr, sizeof(sv_addr)); if (rtn < 0) { perror("sv:bind"); goto err; } /* クライアントからの接続要求の受付 (listen) */ rtn = listen(sid1, 5); if (rtn == -1) { perror("sv:listen"); goto err; } while (1) { /* クライアントからの接続要求の受信 (accept) */ cl_size = sizeof(cl_addr); sid2 = accept(sid1, (struct sockaddr *)&cl_addr, (socklen_t *)&cl_size); if (sid2 < 0) { perror("sv:accept"); goto err; } /* メッセージ通信処理 (send/recv) */ rtn = send(sid2, mesg, sizeof(mesg), 0); if (rtn < 0) perror("sv:send"); /* ソケットの開放 (shutdown,close) */ rtn = shutdown(sid2, 2); if (rtn < 0) perror("sv:shutdown"); close(sid2); } err: /* ソケットの開放 (close) */ close(sid1); exit(0); }
/* */ /* コネクション型クライアントプログラム (hellocl.c) */ /* Usage: hellocl host_name */ /* */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define PROT_NO 5001 /* ポート番号 */ #define BUF_MAX 64 /* 通信バッファサイズ */ static struct sockaddr_in sv_addr; /* サーバアドレス */ static struct hostent *sv_ip; /* サーバIPアドレス */ static int sid; /* ソケット識別子 */ static char buf[BUF_MAX]; /* 通信バッファ */ /* クライアントメイン */ int main(argc, argv) int argc; char *argv[]; /* argv[1]:サーバホスト名 */ { int rtn; /* 返却値 */ /* コネクション型ソケットの作成 (socket) */ sid = socket(AF_INET, SOCK_STREAM, 0); if (sid < 0) { perror("cl:socket"); exit(1); } /* サーバのIPアドレスを取得 */ sv_ip = gethostbyname(argv[1]); if (sv_ip == NULL) { perror("cl:gethostbyname"); exit(1); } /* ソケットの接続要求 (connect) */ bzero((char *)&sv_addr, sizeof(sv_addr)); sv_addr.sin_family = AF_INET; sv_addr.sin_port = htons(PROT_NO); memcpy((char *)&sv_addr.sin_addr, (char *)sv_ip->h_addr, sv_ip->h_length); rtn = connect(sid, (struct sockaddr *)&sv_addr, sizeof(sv_addr)); if (rtn < 0) { perror("cl:connect"); close(sid); exit(1); } /* メッセージ通信処理 (send/recv) */ rtn = recv(sid, buf, BUF_MAX, 0); if (rtn < 0) perror("cl:recv"); printf("%s\n", buf); /* ソケットの開放 (shutdown/close) */ rtn = shutdown(sid, 2); if (rtn < 0) perror("cl:shutdown"); close(sid); exit(0); }
環境はUbuntu8.10 + gccです。
Fedoraでは無いですけど問題は無いはずです。
とりあえず、コンパイルオプションがいらないと思います。
コンパイラオプションを削除すればコンパイルは一応可能です。
警告出まくりですけど。
$ make cc -o hellosv hellosv.c hellosv.c: In function ‘main’: hellosv.c:45: 警告: incompatible implicit declaration of built-in function ‘bzero’ hellosv.c:48: 警告: incompatible implicit declaration of built-in function ‘memcpy’ hellosv.c:50: 警告: passing argument 2 of ‘bind’ from incompatible pointer type hellosv.c:66: 警告: passing argument 2 of ‘accept’ from incompatible pointer type hellosv.c:85: 警告: incompatible implicit declaration of built-in function ‘exit’ cc -o hellocl hellocl.c hellocl.c: In function ‘main’: hellocl.c:31: 警告: incompatible implicit declaration of built-in function ‘exit’ hellocl.c:38: 警告: incompatible implicit declaration of built-in function ‘exit’ hellocl.c:42: 警告: incompatible implicit declaration of built-in function ‘bzero’ hellocl.c:45: 警告: incompatible implicit declaration of built-in function ‘memcpy’ hellocl.c:47: 警告: passing argument 2 of ‘connect’ from incompatible pointer type hellocl.c:51: 警告: incompatible implicit declaration of built-in function ‘exit’ hellocl.c:63: 警告: incompatible implicit declaration of built-in function ‘exit’
ご回答ありがとうございます。
makefileのコンパイルオプションを削除して"make all"を実行したところコンパイルは通り
"hellosv"と"hellocl"が生成されましたが、これらを実行すると「セグメンテーション違反です」
と表示されてしまい、実行することができません。
http://www.asahi-net.or.jp/~vs6k-nkym/pong_compile.html
こちらのWebサイトで解説されているように、socketライブラリーとnslライブラリーを利用するため
コンパイルオプションの"-lsocket"と"-lnsl"は必要な気がするのですが…。
※利用しているコンパイラのバージョンを書き忘れていました。
利用しているバージョンは"gcc version 4.4.0"です。
ご回答ありがとうございます。
"/usr/bin/ld: cannot find -lsocket"というエラーメッセージが表示されていたので
なんとなく、socketがライブラリの検索パスに登録されていないのではないかと感じて
はいたのですが、こうすれば共有ライブラリをシステムに認識させることができるんですね。
大変勉強になりました。
さっそく、"/etc/ld.so.conf"に"/usr/local/lib"を追加後、"/sbin/ldconfig"を実行し、再コンパイル
を行いましたが、残念ながらエラー内容は変わりませんでした。その後、"/etc/ld.so.conf"に追加するのは"socket.h"のある
"/usr/include/sys"なのではないかと思い、再編集後、"/sbin/ldconfig"を実行し、再コンパイル
を行いましたが、やはりエラー内容は変わりませんでした。
とはいえ、なんとなく解決の糸口は見つかったような気がしてきました。
「"hellosv"と"hellocl"が生成」されたのでしたら、コンパイルはできているので ldconfig などの実行は必要ないと思います。
このプログラムは起動時に引数を指定しないとセグメンテーション違反になると思いますが、実行する際に引数は指定されたでしょうか。
hellosv localhost
hellocl localhost
のようにホスト名を引数に指定すれば動くのではないでしょうか。
引数が指定されなくても動くようにプログラムの方も修正すべきだとは思いますが。
恥ずかしながら、まさにその通りでした。
おかげさまで、プログラムの中身を見てどのような引数が起動時に必要か分かるようになりました。
ありがとうございました。
>"hellosv"と"hellocl"が生成されましたが、これらを実行すると「セグメンテーション違反です」
>と表示されてしまい、実行することができません。
取り合えずコンパイル時に警告は出てあたりまえ。「セグメンテーション違反です」で落ちるのも当たり前。
答えをそのまま書くのでは勉強にならないのでヒントだけ。
警告のヒント
1:必要なヘッダが無い。
2:connect(2)の第2引数の型が違う。
セグって落ちるヒント
sv_ip = gethostbyname(argv[1]);
>※利用しているコンパイラのバージョンを書き忘れていました。
> 利用しているバージョンは"gcc version 4.4.0"です。
そういえばこちらも書いていませんでしたね。
まああまり関係ないとは思うけど念のためこちらの環境を書いておきます。
Ubuntuでaptで入れただけです。
$ gcc -v Using built-in specs. Target: i486-linux-gnu コンフィグオプション: ../src/configure -v --with-pkgversion='Ubuntu 4.3.2-1ubuntu12' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu スレッドモデル: posix gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)
試行錯誤の末、なんとか起動できるようになりました。
ありがとうございました。
本気で勉強するなら、以下を薦めておきます。
UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI
とりあえず修正してみました。FreeBSDとdebian で動いています。
% cc -Wall -o hellosv hellosv.c % cc -Wall -o hellosv hellocl.c %
/* */ /* コネクション型のサーバプログラム (hellosv.c) */ /* Usage: hellosv host_name & */ /* */ #include <stdio.h> #include <netdb.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define PROT_NO 5001 static char mesg[] = "Hello world."; static struct sockaddr_in sv_addr; /* サーバアドレス */ static struct sockaddr_in cl_addr; /* クライアントアドレス */ static struct hostent *sv_ip; /* サーバIPアドレス */ static int sid1; /* デーモンソケット識別子 */ static int sid2; /* 子プロセスソケット識別子 */ static int cl_size; /* クライアントアドレスサイズ */ /* サーバメイン */ int main(argc, argv) int argc; char *argv[]; /* argv[1]:サーバホスト名 */ { int rtn; /* 返却値 */ /* コネクション型ソケットの作成 (socket) */ sid1 = socket(AF_INET, SOCK_STREAM, 0); if (sid1 < 0) { perror("sv:socket"); goto err; } /* サーバのIPアドレスを取得 */ sv_ip = gethostbyname(argv[1]); if (sv_ip == NULL) { perror("sv:gethostbyname"); goto err; } /* ソケットに名前を付加 (bind) */ bzero((char *)&sv_addr, sizeof(sv_addr)); sv_addr.sin_family = AF_INET; sv_addr.sin_port = htons(PROT_NO); memcpy((char *)&sv_addr.sin_addr, (char *)sv_ip->h_addr, sv_ip->h_length); rtn = bind(sid1, (struct sockaddr *)&sv_addr, sizeof(sv_addr)); if (rtn < 0) { perror("sv:bind"); goto err; } /* クライアントからの接続要求の受付 (listen) */ rtn = listen(sid1, 5); if (rtn == -1) { perror("sv:listen"); goto err; } while (1) { /* クライアントからの接続要求の受信 (accept) */ cl_size = sizeof(cl_addr); sid2 = accept(sid1, (struct sockaddr *)&cl_addr, (socklen_t *)&cl_size); if (sid2 < 0) { perror("sv:accept"); goto err; } /* メッセージ通信処理 (send/recv) */ rtn = send(sid2, mesg, sizeof(mesg), 0); if (rtn < 0) perror("sv:send"); /* ソケットの開放 (shutdown,close) */ rtn = shutdown(sid2, 2); if (rtn < 0) perror("sv:shutdown"); close(sid2); } err: /* ソケットの開放 (close) */ close(sid1); exit(0); }
/* */ /* コネクション型クライアントプログラム (hellocl.c) */ /* Usage: hellocl host_name */ /* */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define PROT_NO 5001 /* ポート番号 */ #define BUF_MAX 64 /* 通信バッファサイズ */ static struct sockaddr_in sv_addr; /* サーバアドレス */ static struct hostent *sv_ip; /* サーバIPアドレス */ static int sid; /* ソケット識別子 */ static char buf[BUF_MAX]; /* 通信バッファ */ /* クライアントメイン */ int main(argc, argv) int argc; char *argv[]; /* argv[1]:サーバホスト名 */ { int rtn; /* 返却値 */ /* コネクション型ソケットの作成 (socket) */ sid = socket(AF_INET, SOCK_STREAM, 0); if (sid < 0) { perror("cl:socket"); exit(1); } /* サーバのIPアドレスを取得 */ sv_ip = gethostbyname(argv[1]); if (sv_ip == NULL) { perror("cl:gethostbyname"); exit(1); } /* ソケットの接続要求 (connect) */ bzero((char *)&sv_addr, sizeof(sv_addr)); sv_addr.sin_family = AF_INET; sv_addr.sin_port = htons(PROT_NO); memcpy((char *)&sv_addr.sin_addr, (char *)sv_ip->h_addr, sv_ip->h_length); rtn = connect(sid, (struct sockaddr *)&sv_addr, sizeof(sv_addr)); if (rtn < 0) { perror("cl:connect"); close(sid); exit(1); } /* メッセージ通信処理 (send/recv) */ rtn = recv(sid, buf, BUF_MAX, 0); if (rtn < 0) perror("cl:recv"); printf("%s\n", buf); /* ソケットの開放 (shutdown/close) */ rtn = shutdown(sid, 2); if (rtn < 0) perror("cl:shutdown"); close(sid); exit(0); }
Webページに掲載されているソースコードと修正していただいたソースコードを見比べながら
どのように書けば警告が出なくなるのか試すことができ、非常に勉強になりました。
ありがとうございました。
※今後参照される方が分かりやすいように変更箇所を簡単にメモしておきます。
/* */ /* コネクション型のサーバプログラム (hellosv.c) */ /* */ //add #include <string.h> #include <stdlib.h> #include <unistd.h> //fix /* ソケットに名前を付加 (bind) */ rtn = bind(sid1, (struct sockaddr *)&sv_addr, sizeof(sv_addr)); /* クライアントからの接続要求の受信 (accept) */ sid2 = accept(sid1, (struct sockaddr *)&cl_addr, (socklen_t *)&cl_size);
/* */ /* コネクション型クライアントプログラム (hellocl.c) */ /* */ //add #include <stdlib.h> #include <string.h> #include <unistd.h> //fix /* ソケットの接続要求 (connect) */ rtn = connect(sid, (struct sockaddr *)&sv_addr, sizeof(sv_addr));
Webページに掲載されているソースコードと修正していただいたソースコードを見比べながら
どのように書けば警告が出なくなるのか試すことができ、非常に勉強になりました。
ありがとうございました。
※今後参照される方が分かりやすいように変更箇所を簡単にメモしておきます。