プロが教えるわが家の防犯対策術!

Ubuntu 10.10 + gcc4.4 + eclipse で C言語プログラミングをしています。
ソケットを使用したプログラムを試していたのですが、思うように動作しません。
作成したプログラムは以下のようなものです。
・ローカルマシン上で、サーバプログラム、クライアントプログラムを用意する
・サーバ側はソケット作成後、クライアントが接続するまで listen する
・クライアントはサーバに接続したら、接続した旨を表示する
という初歩的なものです。

問題は、サーバ側が accept したときに戻り値 -1 を返却して終了してしまうことです。

以下が作成したソースです。

■■■▼ サーバ側ここから ▼■■■
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_un srv;
socklen_t socklen;

/* ソケット名をコマンド入力で受け取る */
if(argc != 2) {
puts("USAGE: mksock <filename>");
exit(EXIT_FAILURE);
}

/* ソケット作成 */
if((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
exit(EXIT_FAILURE);
}

/* srv 初期化 */
memset(&srv, 0, sizeof(srv));
srv.sun_family = AF_UNIX;
strncpy(srv.sun_path, argv[1], sizeof(srv.sun_path));

/* バインド */
if((bind(sockfd, (struct sockaddr *)&srv, SUN_LEN(&srv))) < 0){
exit(EXIT_FAILURE);
}

/* クライアントからの接続待ち */
if((listen(sockfd, 5)) < 0) {
exit(EXIT_FAILURE);
}
printf("socket available: %s, sockfd=%d\n", srv.sun_path, sockfd);

/* 接続がある限りくりかえす */
int sockResult;
while(1) {
sockResult = accept(sockfd, (struct sockaddr *)&srv, &socklen);
printf("sockResult = %d, sun_path=%s\n", sockResult, srv.sun_path);
if (sockResult < 0)
break;
puts("new connection granted");
}

puts("mksock end");

exit(EXIT_SUCCESS);
}

■■■▲ サーバ側ここまで ▲■■■

●●●▼ クライアント側ここから ▼●●●
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_un cli;
socklen_t socklen;

/* ソケット名をコマンド入力で受け取る */
if(argc != 2) {
puts("USAGE: sockconn <filename>");
exit(EXIT_FAILURE);
}

/* ソケット作成 */
if((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
exit(EXIT_FAILURE);
}

/* クライアント設定 */
memset(&cli, 0, sizeof(cli));
cli.sun_family = AF_UNIX;
strncpy(cli.sun_path, argv[1], sizeof(cli.sun_path));

/* サーバへ接続 */
socklen = SUN_LEN(&cli);
if(connect(sockfd, (struct sockaddr *)&cli, socklen)) {
exit(EXIT_FAILURE);
}
printf("connected to socket %s\n", cli.sun_path);

exit(EXIT_SUCCESS);
}
●●●▲ クライアント側ここまで ▲●●●

これから作成されたバイナリを同一フォルダに置いて、作成ユーザで、カレントディレクトリで実行しました。
以下が実行時の入出力です(カッコ内は実行順序)。

■▼ サーバ側ここから ▼■
$ ./mksock jjj1…(1)
$ socket available: jjj1, sockfd=3
$ sockResult = -1, sun_path=jjj1
$ mksock end
■▲ サーバ側ここから ▲■

●▼ クライアント側ここから ▼●
$ ./sockconn jjj1…(2)
$ connected to socket jjj1
●▲ クライアント側ここから ▲●

上記のように、サーバ側が accept 時に -1 を返却しています。
パーミッションについては以下になっています。

srwxr-xr-x 1 hoge hoge 0 2011-09-04 21:36 jjj1
-rwxr--r-- 1 hoge hoge 86870 2011-09-04 21:36 mksock
-rwxr--r-- 1 hoge hoge 86775 2011-09-04 21:36 sockconn

パーミッションを見る限り、ソケットファイルにはアクセスできているかと。
おそらく環境周りではないかと思いますが、考えつきません。
linux プログラミングに詳しいかた、よろしくお願いいたします。

A 回答 (1件)

こちら、CentOS release 5.6 (Final)


で確認しましたところ、正常に動作しました。
(new connection grantedのメッセージが表示されました。)

>おそらく環境周りではないかと思いますが、考えつきません。
こちらで、再現しないので、環境の問題かと思います。
原因を特定するために、errnoを印字して確認しては、いかがですか。
(必ずしも特定できることが保障されるわけではありませんが・・・)
以下のようにしてください。
printf("sockResult = %d, sun_path=%s,errno=%d\n", sockResult, srv.sun_path,errno);
    • good
    • 0
この回答へのお礼

アドバイスありがとうございました。
おかげで動作するところまでたどり着きました!

以下の手順で調査しました。
(1)アドバイスどおり errno を出力するようにして実行
$ sockResult = -1, sun_path=aaa, errno=22

(2)errno=22 は EINVAL ということだったので、accept の man より「ソケットが接続待ち状態ではない。もしくは、 addrlen が不正である」と判明

(3) 確かに accept の引数の socklen に値を代入していなかったので、srv を sizeof して代入

socklen = sizeof(srv);

(4)実行したら成功!
$ sockResult = 4, sun_path=aaa, errno=0
$ new connection granted

ただ、こちらでも CentOS で動かしてみたら、確かに修正前のソースでも動作しました。
gcc のバージョンか、ディストリの違いによるのか(?)分からないのが気持ちが悪いですが。。。。

いずれにせよ、これで errno の使い方もわかりました。
ありがとうございました!

お礼日時:2011/09/05 23:27

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