send_file() - ソケットによるファイル・データの送信

標準

標準/拡張機能 C/C++ 依存項目
z/OS®UNIX 両方  

形式

#define _OPEN_SYS_SOCK_EXT2
#include <sys/socket.h>

int send_file(int *socket_ptr, struct sf_parms *sf_struct, int options);

機能説明

send_file() 関数は、ソケットに関連した接続によるオープン・ファイル・ハンドルと関連したファイルからデータを送信します。

この関数は、次の引数をとります。

socket_ptr
ソケット・ファイル記述子のポインター。
sf_struct
ヘッダー情報、ファイル情報、トレーラー情報、操作の結果といった、sendfile に必要な変数が設定されている構造体のポインター。詳細は、以下を参照してください。
options
次のオプションのいずれかを指定します。
SF_CLOSE
データが正常に送信された後、または送信のキューに入ったあと接続をクローズします。
SF_REUSE
データが正常に送信された後、または送信のキューに入り既存の接続がクローズされたあとソケットを再利用に準備します。
0
ソケットをクローズしません (オプションなしの場合はゼロを使用)。

Send_File 構造体 - sf_parms

引数 sf_struct は、ファイル記述子、ヘッダー・データ・バッファー、およびトレーラー・データ・バッファーが設定されている、構造体 sf_parms を指します。

構造体 sf_parms<sys/sockets.h> 内に定義されており、以下のエレメントを含みます。
header_data
ファイル・データの前に送信されるヘッダー・データが含まれているバッファーへのポインター。header_length がゼロの場合、NULL ポインターになることがあります。
header_length
header_data のバイト数を指定します。ヘッダー・データが送信されないように指定するには、ゼロに設定する必要があります。
file_descriptor
読み取り用にオープンされたファイルのファイル記述子。これは、送信されるデータが入っているファイルの記述子です。
file_size
file_descriptor に関連したファイルのサイズ (バイト単位)。 このフィールドは、システムが設定します。
file_offset
データ送信を開始するファイルへのバイト・オフセットを指定します。
file_bytes
送信されるファイルからバイト数を指定します。file_bytes を -1 に設定すると、offset からファイル全体が送信されます。 この場合、-1 は、実際のファイル・サイズから file_offset を引いた値に置き換えられます。file_bytes を 0 に設定すると、ファイル・データは送信されず、file_descriptor は無視されます。 file_descriptor が通常のファイルでない場合は、file_bytes に特定の値を指定する必要があります。ただし、この操作の実行時に file_descriptor のファイルに正規の「ファイル終わり」の指示がある場合、または単にバイトが到着するときにバイトの永続転送を行う場合は除きます。
trailer_data
ファイル・データの後に送信されるトレーラー・データがあるバッファーへのポインター。
trailer_length
trailer_data のバイト数を指定します。
bytes_sent
この send_file() の呼び出しで送信されたバイト数。 すべてのデータを送信するために複数の send_file() 呼び出しを実行する必要がある場合 (シグナル処理のため)、このフィールドには、最後の send_file() 呼び出しの値が入ります。これは、すべての send_file() 呼び出しの値ではありません。このフィールドは、システムによって設定されます。

send_file() 関数は、header_data が指すバッファーの header_length バイト、file_descriptor に関連したファイルの file_bytestrailer_data が指すバッファーの trailer_length バイトの順に socket_ptr が指すソケットに関連した接続に関するデータの書き込みを実行します。

データが送信されると、sf_struct 内のエレメントが更新されるので、send_file() 関数がシグナルで割り込まれても、アプリケーションは send_file() を再発行するだけで済みます。

実際のファイル・サイズより大きい file_offset >、または実際のファイル・サイズから file_offset > を引いた値より大きい file_bytes がアプリケーションによって設定されると、戻り値は -1 になり、errno は EINVAL に設定されます。

ソケット・ファイル記述子に O_NONBLOCK が設定されていると、関数は EWOULDBLOCK または EAGAIN に設定された errno と 共に -1 を戻します。あるいは、すべてのデータが送信される前に終了します。O_NONBLOCK が設定されていない場合は、要求したデータが送信されるまで send_file() はブロック化します。

SF_CLOSE および SF_REUSE が有効なのは、すべてのデータが正常に送信された場合のみです。

options = SF_REUSE であり、ソケットの再利用がサポートされていない場合、ソケットはクローズされ、socket_ptr が指すソケットが -1 に設定されます。詳細は、アプリケーションの使用法を参照してください。

アプリケーションの使用法

関数 send_file() は、accept_and_recv() と共に使用することで、接続指向のサーバーが短い接続時間と高い接続率で効率的なファイル転送能力を得ることができるように設計されています。

accept_and_recv() の最初の呼び出しでは、アプリケーションにおいて accept_socket が指すソケットを -1 に設定することをお勧めします。これにより、受信ソケットが割り当てられます。send_file() の呼び出しでは、アプリケーションがソケットの再利用 (options = SF_REUSE) を要求しても、システムがソケット再利用をサポートしていないと、socket_ptr が指すソケットはクローズされ、socket_ptr が指すソケットは、-1 に設定されます。次に、アプリケーションは、この値を次の accept_and_recv() の呼び出しに渡します (accept_socket = *socket_ptr を設定することにより)。

accept_and_recv() 関数と send_file() 関数によってもたらされるパフォーマンスの向上を最大限に利用するには、ループで親プロセスが子プロセス・スレッドを受け入れてスピンオフするプロセス/スレッド・モデルとは異なるプロセス/スレッド・モデルが必要です。親/プロセス・スレッドは除去されます。複数の worker プロセス/スレッドが作成されてから、各 worker プロセス/スレッドはループで accept_and_recv() 関数と send_file() 関数を実行します。accept_and_recv() および send_file() によるパフォーマンスの向上により、バッファー・コピー数の削減、再利用ソケット、最適スケジューリングなどの利点があります。

注: 関数 send_file() は、それ単独で長時間のソケット接続に有効です。accept_and_recv() とペアである必要はありません。send_file() の呼び出し後にソケットを開いたままにしておくには、options パラメーターに 0 を指定します。

戻り値

send_file() は、正常に実行された場合は 0 を戻します。

要求にシグナルが割り込んだか、またはデータ送信中に非ブロック化記述子がブロック化された場合は、1 が戻ります。 sf_parms 構造体は送信されたデータにそって更新されるので、send_file() を再度呼び出しすることで、sf_parms 構造体を変更することなく、割り込まれた位置から操作を続行することができます。

正常に実行されなかった場合、send_file() は -1 を戻して、errno を次のいずれかの 値に設定します。

エラー・コード
説明
EACCES
適切な特権が呼び出しプロセスにありません。
EAGAIN
socket_ptr は非ブロック・モードであり、使用可能なデータ・バッファー がないか、バッファーが使用可能になる前に SO_SNDTIMEO タイムアウト値に達しました。
EBADF
次のいずれかが発生しました。
  1. socket_ptr が有効な記述子でないか、書き込み用にオープンされていませんでした。
  2. file_descriptor が有効な記述子でないか、読み取り用にオープンされていませんでした。
ECONNABORTED
接続が打ち切られました。
ECONNRESET
接続はピアによって強制的にクローズされました。
EFAULT
socket_ptrfile_sizeheader_data、または trailer_data が指すデータ・バッファーが無効でした。
EINTR
send_file() は、データが送信される前にキャッチされたシグナルによって割り込まれました。
EINVAL
options によって指定された値は無効です。
EIO
入出力エラーが発生しました。
EMSGSIZE
メッセージのサイズが大きすぎて、ソケットの要求どおり一度にすべてを送信することができません。
ENETDOWN
宛先に到達するためのローカル・インターフェースが不明です。
ENETUNREACH
宛先への経路が存在しません。
ENOBUFS
バッファー・スペースを使用できません。
ENOMEM
メモリーが不十分なので、操作を完了できませんでした。
ENOSR
STREAMS リソースが不十分なため、操作を完了できませんでした。
ENOSYS
この関数は、現在の環境でサポートされていません。
ENOTCONN
ソケットが接続していません。
ENOTSOCK
socket_ptr 引数が指すファイル記述子は、ソケットを参照していません。
EPIPE
ソケットが書き込みに対してシャットダウンされているか、またはソケットが接続モードであっても接続されていません。
EWOULDBLOCK
socket_ptr は非ブロック・モードであり、使用可能なデータ・バッファー がないか、バッファーが使用可能になる前に SO_SNDTIMEO タイムアウト値に達しました。

関連情報