Apakah panggilan paralel untuk mengirim / menerima pada soket yang sama valid?

127
  1. Bisakah kita memanggil kirim dari satu utas dan menerima dari yang lain pada soket yang sama?
  2. Bisakah kita memanggil banyak pengiriman secara pararel dari utas berbeda pada soket yang sama?

Saya tahu bahwa desain yang baik harus menghindari ini, tetapi saya tidak jelas bagaimana perilaku sistem API ini. Saya tidak dapat menemukan dokumentasi yang bagus juga untuk hal yang sama.

Setiap petunjuk arah akan membantu.

Jay
sumber
3
mengapa Anda mengklaim bahwa melakukan itu adalah praktik yang buruk? Ini terlihat baik bagi saya karena Anda mendengarkan dan menerima dari utas yang berbeda.
TheMathNoob

Jawaban:

92

POSIX mendefinisikan send / recv sebagai operasi atom, jadi dengan asumsi Anda berbicara tentang POSIX send / recv maka ya, Anda dapat memanggil mereka secara bersamaan dari beberapa utas dan semuanya akan berfungsi.

Ini tidak berarti bahwa mereka akan dieksekusi secara paralel - dalam kasus beberapa pengiriman, yang kedua kemungkinan akan diblokir sampai yang pertama selesai. Anda mungkin tidak akan melihat sebanyak ini, karena pengiriman selesai setelah memasukkan datanya ke dalam buffer socket.

Jika Anda menggunakan soket SOCK_STREAM, mencoba melakukan hal-hal yang paralel cenderung tidak berguna karena mengirim / menerima mungkin mengirim atau menerima hanya sebagian dari pesan, yang berarti berbagai hal dapat terpecah.

Memblokir send / recv pada soket SOCK_STREAM hanya memblokir sampai mereka mengirim atau menerima setidaknya 1 byte, sehingga perbedaan antara pemblokiran dan non-pemblokiran tidak berguna.

Chris Dodd
sumber
1
@ Joo: soket SOCK_DGRAM didokumentasikan sebagai "menjaga batas-batas pesan", yang tidak terlalu jelas. Dari melihat sumber-sumber kernel linux Anda setidaknya dapat melihat bahwa masing-masing mengirim dan menerima berurusan dengan satu paket secara atom (setidaknya untuk udp).
Chris Dodd
2
@Kedar: tidak yakin apa yang Anda maksud. Sebuah sendpengembalian segera setelah data ditempatkan ke dalam mengirim buffer, dan data dikirim pada melalui tumpukan netowrk dan keluar ke jaringan asynchronous. Jadi, jika Anda memiliki satu utas pengiriman dan satu utas penerima, sangat mungkin (bahkan mungkin) utas utas untuk mengirim banyak paket sebelum utas penerima menerima paket pertama. Sepenuhnya asinkron dan tidak simultan.
Chris Dodd
6
@ChrisDodd, dapatkah Anda memberikan tautan untuk "POSIX mendefinisikan send / recv sebagai operasi atom"?
suitianshi
2
@ suuitianshi: Dokumen standar POSIX 1003.1c mencantumkan semua fungsi di 1003.1 yang reentrant (aman untuk dipanggil dari utas) dan yang tidak. Sayangnya, saya tidak mengetahui salinan online gratis yang tersedia di mana saja.
Chris Dodd
2
@ ChrisDodd Saya telah menemukan salinan di unix-systems.org/version4 dan saya bisa melihat daftar Tabel Antarmuka Sistem pada bab 7.1 tetapi tidak melihat di mana ia mencantumkan fungsinya sebagai operasi atom. Bukan untuk meragukan Anda, tetapi bisakah Anda membagikan / mengedit jawaban Anda untuk membenarkan poin Anda dalam dokumen?
user153882
17

Deskriptor soket milik proses, bukan ke utas tertentu. Oleh karena itu, dimungkinkan untuk mengirim / menerima ke / dari soket yang sama di utas yang berbeda, OS akan menangani sinkronisasi.

Namun, jika urutan pengiriman / penerimaan adalah signifikan secara semantik, Anda sendiri (masing-masing kode Anda) harus memastikan urutan yang benar antara operasi di utas berbeda - seperti yang selalu terjadi pada utas.

Adrian Willenbücher
sumber
4

Saya tidak melihat bagaimana menerima secara paralel dapat mencapai apa pun. Jika Anda memiliki pesan 3 byte, 1 utas dapat memperoleh 2 byte pertama dan satu lagi byte terakhir, tetapi Anda tidak memiliki cara untuk mengetahui yang mana. Kecuali jika pesan Anda panjangnya hanya satu byte, tidak mungkin Anda dapat andal membuat apa pun dengan menerima banyak utas.

Beberapa pengiriman mungkin berhasil, jika Anda mengirim seluruh pesan dalam satu panggilan, tetapi saya tidak yakin. Mungkin saja satu bisa menimpa yang lain. Tentu tidak akan ada manfaat kinerja untuk melakukannya.

Jika beberapa utas perlu dikirim, Anda harus menerapkan antrian pesan yang disinkronkan. Memiliki satu utas yang melakukan pengiriman aktual yang membaca pesan dari antrean dan utas lainnya enqueue seluruh pesan. Hal yang sama akan berfungsi untuk menerima, tetapi utas penerima harus mengetahui format pesan sehingga dapat membatalkan deserialisasi dengan benar.

Nuh
sumber
9
Jika Anda menggunakan soket SOCK_DGRAM, setiap recv akan mendapatkan satu datagram; tidak akan pernah terpecah antara recvs
Chris Dodd
2
@ ya, saya setuju recvs paralel tidak bisa mencapai apa pun. Itu sebabnya saya belum menanyakannya. Pertanyaan saya adalah kirim / terima pararel dan kemudian beberapa dikirim pararel. Jawaban Anda memang memberi wawasan tentang pengiriman paralel. Terima kasih untuk hal yang sama.
Jay
1
@ Chris poin bagus. Saya mengasumsikan TCP. @ Jay Anda mungkin mengklarifikasi pertanyaan "Bisakah kita memanggil mengirim / menerima parallely" terdengar seperti Anda ingin menerima secara paralel.
noah