Linux: Zaman aşımına sahip soketten okuma veya geri alma var mı?


106

Zaman aşımıyla soketten nasıl veri okumayı deneyebilirim? Biliyorum, select, pselect, anket, bir zaman aşımı alanına sahiptir, ancak bunların kullanılması tcp reno yığınında "tcp hızlı yolu" devre dışı bırakır.

Sahip olduğum tek fikir, bir döngüde recv (fd, ..., MSG_DONTWAIT) kullanmaktır


Konu kullanma seçeneği de var :) ancak iş parçacığı sinyalleri hala gerekli
osgx

Yanıtlar:


189

Setsockopt işlevini alma işlemlerinde bir zaman aşımı ayarlamak için kullanabilirsiniz :

SO_RCVTIMEO

Bir giriş işlevinin tamamlanana kadar bekleyeceği maksimum süreyi belirten zaman aşımı değerini ayarlar. Bir giriş işleminin tamamlanması için ne kadar bekleneceği ile ilgili limiti belirten saniye ve mikrosaniye sayısı ile bir zamanlama yapısını kabul eder. Bir alım işlemi ek veri almadan bu kadar süre bloke olmuşsa, veri alınmazsa kısmi sayım veya hata no [EAGAIN] veya [EWOULDBLOCK] olarak ayarlanarak geri dönecektir. Bu seçenek için varsayılan sıfırdır ve bu, bir alma işleminin zaman aşımına uğramayacağını belirtir. Bu seçenek zamana dayalı bir yapı alır. Tüm uygulamaların bu seçeneğin ayarlanmasına izin vermediğini unutmayın.

// 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);

Bildirildiğine göre Windows'ta bu, aramadan önce yapılmalıdır bind. bindLinux ve OS X'te önce veya sonra yapılabileceğini deneyle doğruladım .


1
Bu cevap kıçımı kurtardı. Başarısız olan bu kıvrımlı "seçme" saçmalığını uygulamakta kaldım. Bu hemen işe yaradı, çok daha basit.
MiloDC

Linux kodunu kullandığım için pencerelerde zaman aşımının çalışmamasının nedeni budur. Teşekkürler. Windows kullanılmıyorsa struct timeval tv;, select () de çalışmayacağı anlamına mı gelir? Select () kodumu pencerelere taşımayı denedim ve hemen zaman aşımına uğradı, timeval'da ayarladığım değeri görmezden geliyor gibi görünüyor.
kuchi

1
Zaman aşımı değerini 5 saniyeye ayarladım. Gelen veri olup olmadığına bakılmaksızın her okuma döngüsü neden her zaman 5 saniye sürüyor?
Han

bu ayrıca bağlama işleminden sonra bile pencerelerde çalışır. Windows 10'da denendi
cahit beyaz

1
@ user463035818 Bu cevap olmaması gerektiğini iddia ediyor.
Tomeamis

22

C'yi recvkullanarak işlevinize bir zaman aşımı eklemek için bazı basit kodlar poll:

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;
}

bu tam olarak beklendiği gibi çalışmaz. pollen az bir bayt veya zaman aşımı almayı bekleyecek, oysa recvişlevi çağırırken sizeof(buf)baytları bekleyecek ve bu sayı henüz gelmediyse, ancak bu sefer zaman aşımı olmadan tekrar bloklanmasına neden olacak .
LoPiTaL

0

// WINDOWS için bağlama işleminden sonra da çalışır

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

-1

Düzenli bir engelleme için bir işleyici yükleyin SIGALRM, ardından alarm()veya ualarm()önce kullanın recv(). Alarm çalmaya başlarsa, ayarlı olarak recv()bir hata döndürecektir .errnoEINTR


8
alarmlar (ve sinyaller) bu görevin yanlış yoludur. Tcp hızlı yolunu kullanmak istiyorsam, minimum gecikmeye ihtiyacım var. Sinyaller yavaş.
osgx

2
@osgx Sinyal yalnızca bir zaman aşımı varsa oluşur.
David Schwartz

-4

LINUX

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));

PENCERELER

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

NOT : Bu ayarı bind()düzgün çalışma için işlev çağrısından önce koydunuz


4
Bu soru yıllar önce zaten cevaplandı. Çözümünüz hangi yeni değeri getiriyor?
Maciej Jureczko

Bu ayarı düzgün çalışma için bind () işlev çağrısından önce koydunuz, bu bölüm
ans'da
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.