8

タイトルに記載されているように、それに応じたアドレスを使用してUNIXドメインタイプのソケットをconnect()で呼び出すと、エラーENOENT:no such fileordirectoryが発生します。

2つのソケットは適切に初期化され、それに応じてソケットファイルが作成およびバインドされます。サーバーソケットとクライアントソケットは異なるプロセスで実行されますが、クライアントプロセスはfork()-edとexecl()-edです。これは、クライアントソケットの設定に使用するクライアントソケットとサーバーソケットのアドレスを解析する方法でもあります。サーバープロセスはpthreadを使用しています。

これが私のconnect()の試みです:

struct sockaddr_un address;
address.sun_family = AF_UNIX;
memcpy(address.sun_path, filepath.c_str(), filepath.length());
address.sun_path[filepath.length()] = '\0';

if(-1 == connect(this->unix_domain_descriptor_.descriptor(),       \
                (struct sockaddr*)&address,                       \
                size))
{
    global::ExitDebug(-1, "connect() failed", __FILE__, __LINE__);
    return -1;
}

次のようなサイズのさまざまな値を試しました。

//  this is from unix(7) man page. It doesn't work neither with nor without "+1"
socklen_t size =  offsetof(struct sockaddr_un, sun_path);
          size += strlen(address.sun_path) + 1;

//  this is from one of my books about linux programming
socklen_t size = sizeof(address);

//  this is from a sample code which I found at the internet
socklen_t size = sizeof(address.sun_family) + strlen(address.sun_path);

//  Update 1: 
socklen_t size = SUN_LEN(&address);

//  this is what I tried out after looking into the declaration
//  of struct sockaddr_un
socklen_t size = strlen(address.sun_path);

驚いたことに、最後の1つを除くすべての初期化により、 EINVAL: connect()の無効な引数エラーが発生し、 ENOENT:最後のものだけでそのようなファイルまたはディレクトリが発生しません。私はインターネットからすべての例を試しましたが、成功しませんでした。そして明らかに、socklen_tをsize_tまたはintと交換しても何も変わりません。

私はすでにこれをチェックしました:

  • address.sun_pathには、ルートディレクトリから始まる正しいソケットファイルパスが含まれています
  • address.sun_pathの長さは61文字です
  • address.sun_familyはAF_UNIX/AF_LOCALに設定されています
  • address.sun_familyのサイズは2バイトです
  • 両方のソケットの作成とバインドでエラーは発生しません
  • サーバーソケットはリスニング状態です
  • sizeof(address)は、本来あるべき110を返します。

ここで、マニュアルページの例が機能しなかった理由と、linux.die.netまたはwww.kernel.orgで更新されていない変更があったかどうか疑問に思いました。私のOSは、関連するものであればDebianSqueezeです。

私が間違っていることについて何か考えはありますか?そしてそれを解決する方法は?さらにコードが必要な場合や質問がある場合は、遠慮なく私に質問してください(おそらくこれを述べる必要はありませんが、これが私の最初の投稿です>。<)。

ところで、私の悪い英語でごめんなさい

アップデート2

解決しました。わかりやすくするために、以下の追加の回答で投稿します。

4

2 に答える 2

2

ソケットを適切に処理していることがわかった後、connect() のコードを少し変更したところ、動作するようになりました。変数の宣言の後に次の行を追加しました。

memset(&address, 0, sizeof(struct sockaddr_un));

機能させるために変数全体を0に設定する必要がある理由を誰かが知っていますか? これは新しいトピックで質問する必要がありますか、それともここで質問できますか?

于 2012-07-25T10:55:38.067 に答える
0

glibc マニュアルからの引用:

sun_familyコンポーネントのサイズとファイル名文字列の文字列の長さ (割り当てサイズではありません!)の合計として、ローカル名前空間のソケット アドレスの LENGTH パラメータを計算する必要があります。これは、マクロを使用して実行できますSUN_LEN

  • マクロ: int SUN_LEN (_struct sockaddr_un *_ PTR)
    マクロは、ローカル名前空間のソケット アドレスの長さを計算します。

次のでは、失敗したと言う計算を使用しています。

size = (offsetof (struct sockaddr_un, sun_path)
       + strlen (name.sun_path) + 1);

しかし、そのマクロを試してみるべきです。何かが変更された場合、または例が間違っていた場合でも、そのマクロが意図したとおりに機能する可能性は十分にあります。もしそうなら、あなたはその内部を見ることができます。一見すると、マクロには+ 1すべての例で使用されている部分が欠けているように見えます。これは、「割り当てサイズではありません!」を使用するようにというマニュアルの警告と一致します。あなたの投稿によると、これはどちらも機能しませんでした+ 1が、可能性はわずかです。

好奇心から、パスの長さはどれくらいですか? 構造体で提供されるフィールドがそれを保持するのに十分な大きさであるかどうかを確認しましたか? sizeof(address.sun_path)あなたの実装には何がありますか?予約されていないメモリにコピーしていて、次の関数呼び出しでパスの一部が上書きされるのではないかと思います。

于 2012-07-24T13:27:59.067 に答える