Saya menggunakan send() alih-alih write() yang tidak menangani sinyal :
bzero(buffer, MAX_SIZE_BUFFER);
n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1);
printf("after read%d\n", n);
if (n <= 0)
{
break;
}
n2 = send(newsockfd, buffer, n, MSG_NOSIGNAL);
if (n2 == -1)
{
close(sockfd);
close(newsockfd);
return;
}
if (n2 != n)
{
break;
}
Pemrograman soket bisa agak rumit, karena Anda sering kali tidak mengetahui bahwa telah terjadi kesalahan hingga beberapa waktu kemudian.
Misalnya, jika mesin yang Anda tuju mati secara tidak normal, panggilan tulis mungkin berhasil (karena Anda dapat menulis ke buffer OS internal Anda), namun gagal selama panggilan tertutup.
Kecuali jika Anda memiliki cara lapisan aplikasi untuk memverifikasi bahwa soket aktif (yaitu, mengirim pesan dan meminta tanggapan dalam jangka waktu tertentu), Anda tidak memiliki cara untuk mengetahuinya. Jika Anda menggunakan protokol standar, sesuatu mungkin sudah ada untuk menangani kesalahan.
Jadi jawaban singkatnya adalah Anda perlu memeriksa pengembalian kesalahan dari hampir setiap panggilan yang menyentuh soket ( baca, tulis, tutup, dll ... ).
Cara untuk memeriksa apakah Anda dapat menulis ke soket, secara mengejutkan, mencoba dan menulis ke sana :-)
Jika soket telah ditutup, Anda akan mendapatkan -1
mengembalikan kode dari write
dan Anda dapat memeriksa errno
untuk melihat apa masalahnya.
Jika soket masih valid tetapi Anda tidak dapat menulis data apa pun saat ini, write
akan mengembalikan 0. read
call juga berperilaku serupa, mengembalikan -1
jika ada masalah.
Pada dasarnya, untuk write
:
- jika Anda mendapatkan kembali
-1
, ada masalah dan Anda harus memeriksaerrno
untuk melihat apakah dapat dipulihkan atau fatal. - Jika Anda mendapatkan kembali
0
, maka Anda tidak dapat menulis apa pun saat ini (mungkin backlog jaringan atau masalah lain tetapi jelas tidak (belum) fatal). - Jika Anda mendapatkan nilai kurang dari yang Anda inginkan, maka beberapa dari data telah dikirim. Sesuaikan pointer Anda sehingga Anda dapat mencoba mengirim sisanya di siklus berikutnya. Jangan jangan menganggap nilai pengembalian positif berarti seluruh blok telah dikirim.
- Jika Anda mendapatkan kembali nomor yang sama dengan jumlah byte yang Anda coba kirim, seluruh buffer telah diterima untuk pengiriman.
- Jika Anda mendapatkan kembali lebih dari apa yang Anda minta untuk dikirim, kirim email ke pengembang kernel dengan beberapa komentar tajam. Linus dkk akan menyukainya :-)
Perbarui: Seperti yang ditunjukkan kafe di komentar, saya lupa memperhitungkan penanganan sinyal. Anda harus mengabaikan sinyal pipa yang rusak atau write
akan gagal secara internal dengan menaikkan sinyal itu.
Anda dapat melakukannya dengan memasukkan:
struct sigaction new_actn, old_actn;
new_actn.sa_handler = SIG_IGN;
sigemptyset (&new_actn.sa_mask);
new_actn.sa_flags = 0;
sigaction (SIGPIPE, &new_actn, &old_actn);
sebelum mulai menggunakan fungsi soket. Anda kemudian dapat menggunakan:
sigaction (SIGPIPE, &old_actn, NULL);
untuk memulihkan penanganan sinyal sebelumnya.