readの正しい使い方、writeの正しい使い方

※2012年5月2日、追記。

下記のコードよりもcopybenchのコードを参考にした方がいいかもしれない。



C言語: write(2)の正しい使い方というページがあったのだが、今は見ることが出来なくなっているので、似たような内容を残しておくことにした。

正しい使い方とはつまり、システムコールは割り込まれて中断することがあるからちゃんとエラーチェックをしましょう、ということだ。

以下に、writeを使用するためのソースコードを転載する。

/* http://www.koders.com/c/fidBA4A85F16684724E234A9F3D52154B6A3EE76852.aspx?s=md5 */

ssize_t full_write(int fd, const void *buf, size_t len)
{
	ssize_t cc;
	ssize_t total;

	total = 0;

	while (len) {
		cc = safe_write(fd, buf, len);

		if (cc < 0)
			return cc;	/* write() returns -1 on failure. */

		total += cc;
		buf = ((const char *)buf) + cc;
		len -= cc;
	}

	return total;
}

/* http://www.koders.com/c/fid1D28BE2FE0F7496591C635321BDFC406ED821089.aspx?s=md5 */

ssize_t safe_write(int fd, const void *buf, size_t count)
{
	ssize_t n;

	do {
		n = write(fd, buf, count);
	} while (n < 0 && errno == EINTR);

	return n;
}

readも同じような処理が必要なので、以下のような関数を使う。

/* http://www.koders.com/c/fidE71B6BE5B9B1AE1265F1CFBA2DB698715258B0F5.aspx?s=ftp */

int full_read(int fd, char *buf, int len)
{
	int cc;
	int total;

	total = 0;

	while (len > 0) {
		cc = read(fd, buf, len);

		if (cc < 0)
			return -1;

		if (cc == 0)
			break;

		buf += cc;
		total += cc;
		len -= cc;
	}

	return total;
}

/* http://www.koders.com/c/fidA918F638FF7469723CAC99A84826115C1310BC35.aspx?s=ftp */

ssize_t safe_read(int fd, void *buf, size_t count)
{
	ssize_t n;

	do {
		n = read(fd, buf, count);
	} while (n < 0 && errno == EINTR);

	return n;
}

ネットワークアプリケーションの場合は、さらにSIGPIPEシグナルを無視する処理が必要らしい。

関連:Programming UNIX Sockets in C - Frequently Asked Questions