Linux: มีการอ่านหรือรับข้อมูลจากซ็อกเก็ตที่หมดเวลาหรือไม่?


106

ฉันจะพยายามอ่านข้อมูลจากซ็อกเก็ตแบบหมดเวลาได้อย่างไร ฉันรู้ว่าเลือกเลือกแบบสำรวจมีฟิลด์หมดเวลา แต่การใช้พวกเขาปิดใช้งาน "tcp fast-path" ใน tcp reno stack

ความคิดเดียวที่ฉันมีคือใช้ recv (fd, ... , MSG_DONTWAIT) ในวง


นอกจากนี้ยังมีตัวเลือกในการใช้เธรด :) แต่ยังคงต้องการสัญญาณเธรด
osgx

คำตอบ:


190

คุณสามารถใช้ฟังก์ชันsetsockoptเพื่อกำหนดระยะหมดเวลาของการดำเนินการรับ:

SO_RCVTIMEO

ตั้งค่าการหมดเวลาที่ระบุระยะเวลาสูงสุดที่ฟังก์ชันอินพุตจะรอจนกว่าจะเสร็จสิ้น ยอมรับโครงสร้างเวลาที่มีจำนวนวินาทีและไมโครวินาทีที่ระบุขีด จำกัด ระยะเวลาที่ต้องรอให้การดำเนินการป้อนข้อมูลเสร็จสมบูรณ์ หากการดำเนินการรับถูกบล็อกในช่วงเวลานี้โดยไม่ได้รับข้อมูลเพิ่มเติมการดำเนินการจะกลับมาพร้อมกับการนับบางส่วนหรือตั้งค่าผิดพลาดเป็น [EAGAIN] หรือ [EWOULDBLOCK] หากไม่มีการรับข้อมูล ค่าเริ่มต้นสำหรับตัวเลือกนี้คือศูนย์ซึ่งบ่งชี้ว่าการดำเนินการรับจะไม่หมดเวลา ตัวเลือกนี้ใช้โครงสร้างเวลา โปรดทราบว่าการใช้งานบางอย่างไม่อนุญาตให้ตั้งค่าตัวเลือกนี้

// LINUX
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

// WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);

// MAC OS X (identical to Linux)
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

รายงานบน Windows bindนี้ควรจะทำก่อนที่จะเรียก ฉันได้ตรวจสอบโดยการทดลองแล้วว่าสามารถทำได้ก่อนหรือหลังbindบน Linux และ OS X


1
คำตอบนี้ช่วยชีวิตฉันไว้ ฉันติดอยู่กับการใช้อึที่ "เลือก" ที่ซับซ้อนและไม่ประสบความสำเร็จ สิ่งนี้ได้ผลทันทีง่ายกว่ามาก
MiloDC

ตอนนี้เป็นสาเหตุที่การหมดเวลาบน windows ไม่ทำงานเพราะฉันใช้รหัสสำหรับ linux ขอบคุณ. ถ้า windows ไม่ได้ใช้struct timeval tv;หมายความว่า select () จะไม่ทำงานด้วยหรือเปล่า? ฉันลองย้ายรหัส select () ไปที่ windows แล้วมันก็หมดเวลาทันทีดูเหมือนว่ามันจะไม่สนใจค่าที่ฉันตั้งไว้ในช่วงเวลา
kuchi

1
ฉันตั้งค่าการหมดเวลาเป็น 5 วินาที เหตุใดจึงใช้เวลา 5 วินาทีในแต่ละรอบการอ่านเสมอไม่ว่าจะมีข้อมูลเข้าหรือไม่ก็ตาม
ฮัน

นอกจากนี้ยังใช้งานได้กับ windows แม้ว่าจะทำการผูก พยายามบน windows 10
cahit beyaz

1
@ user463035818 คำตอบนี้อ้างว่าไม่ควร
Tomeamis

22

นี่คือรหัสง่ายๆในการเพิ่มเวลานอกให้กับrecvฟังก์ชันของคุณโดยใช้pollใน C:

struct pollfd fd;
int ret;

fd.fd = mySocket; // your socket handler 
fd.events = POLLIN;
ret = poll(&fd, 1, 1000); // 1 second for timeout
switch (ret) {
    case -1:
        // Error
        break;
    case 0:
        // Timeout 
        break;
    default:
        recv(mySocket,buf,sizeof(buf), 0); // get your data
        break;
}

สิ่งนี้จะไม่ได้ผลอย่างที่คาดไว้ pollจะรอรับอย่างน้อยหนึ่งไบต์หรือหมดเวลาในขณะที่เมื่อเรียกใช้recvฟังก์ชันจะรอเป็นsizeof(buf)ไบต์ทำให้บล็อกอีกครั้งหากยังไม่ถึงจำนวนนี้ แต่เวลานี้ไม่มีการหมดเวลา
LoPiTaL

0

// ใช้งานได้หลังจากการดำเนินการผูกสำหรับ WINDOWS

DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);

-1

ติดตั้งจัดการหาSIGALRMแล้วใช้alarm()หรือก่อนที่จะปิดกั้นปกติualarm() recv()หากปลุกไปปิดที่recv()จะกลับข้อผิดพลาดกับชุดerrnoEINTR


8
การเตือนภัย (และสัญญาณ) เป็นวิธีที่ไม่ถูกต้องสำหรับงานนี้ หากฉันต้องการใช้ tcp fast path มากกว่าที่ฉันต้องการเวลาแฝงน้อยที่สุด สัญญาณช้า
osgx

2
@osgx สัญญาณจะเกิดขึ้นก็ต่อเมื่อหมดเวลา
David Schwartz

-4

ลินุกซ์

struct timeval tv;
tv.tv_sec = 30;        // 30 Secs Timeout
tv.tv_usec = 0;        // Not init'ing this can cause strange errors
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));

WINDOWS

DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));

หมายเหตุ : คุณได้ตั้งค่านี้ก่อนbind()เรียกใช้ฟังก์ชันเพื่อให้ทำงานได้อย่างเหมาะสม


4
คำถามนี้ได้รับคำตอบแล้วเมื่อหลายปีก่อน โซลูชันของคุณให้คุณค่าใหม่อะไรบ้าง?
Maciej Jureczko

คุณได้ตั้งค่านี้ก่อนการเรียกใช้ฟังก์ชัน bind () เพื่อให้ทำงานได้อย่างเหมาะสมส่วนนี้ไม่ได้กล่าวถึงใน ans
vivek
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.