2016-08-05 6 views
0

У меня есть ресурс http, размер которого составляет 3 ГБ.urllib2.urlopen (url) .read() синхронизирован в виртуальной машине Os x 10.11 (Vmware Workstation 12 pro)

У меня есть некоторые коды, как показано ниже.

#the url is actually a http resource which is 3GB. 
res = urllib2.urlopen(url, timeout = 10) 
data = res.read(1024) 
while data: 
    data = res.read(1024) 

В рабочей станции Vmware 11 или ниже, она работает fine.But в VMWare Workstation 12, он дает мне ошибку.

Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 384, in read 
    data = self._sock.recv(left) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 612, in read 
    s = self.fp.read(amt) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 384, in read 
    data = self._sock.recv(left) 
socket.timeout: timed out 

Я использую сафари для загрузки ресурса на рабочей станции Vmware 12, он отлично работает. И , если ресурс меньше, чем такой размер, как 10K, он также отлично работает.

+1

Вы пытались удалить 'timeout = 10' и посмотреть, обрабатывается ли запрошенный URL-адрес в течение периода ожидания по умолчанию? – Eduard

+0

@EduardDaduya. Если я удалю таймаут, поток застрянет навсегда. –

+0

Мои извинения, я неправильно понял проблему, вы извлекаете данные через urlopen успешно, но чтение извлеченных данных повышает указанное исключение. Что-то, с чем я еще не сталкивался. Я считаю, что это объяснение поможет вам с вашей текущей проблемой. Http://stackoverflow.com/a/26765074/1809168 – Eduard

ответ

0

Они исправлены в VMware Fusion 8.5.7! См https://communities.vmware.com/thread/544049

Я не могу предоставить вам ответ прямо сейчас, и то, что я должен сказать, что это немного больше, чем комментарий, но я испытываю такой же вопрос в VMWare Fusion Pro 8.5 на 10.12 с Питона urllib2. Это не имеет никакого отношения к urllib2.

Я начал получать эту проблему случайно во время сеансов передачи и после некоторой отладки Wireshark определил, что это произошло из-за того, что окно TCP достигло 0 на ресивере. По какой-то причине он никогда не обновляется.

Если вы не знаете, что такое TCP-окно, это в основном размер буфера приема на одном конце TCP-соединения. Этот буфер должен расширять и заключать контракты в качестве механизма управления перегрузкой во время нормальной передачи, но что не должно происходить, получается, что окно застряло на 0.

Причина, по которой ваши сеансы работают для передач менее 10 тыс., Объясняется тем, что TCP по умолчанию Окно обычно составляет около 8k. Все, что меньше этого, вы даже не пополните принимающий буфер. Больше, и вы в основном надеетесь, что вы обрабатываете данные быстрее, чем вы их получите.

Чтобы воспроизвести проблему на моей локальной машине, вот две [ужасно] написанные программы на C, которые вы можете компилировать с помощью cc client.c -o client и cc server.c -o server. Запустите клиент на виртуальной машине и сервере на локальном компьютере.

server.c:

/* server.c */ 
/* A simple server in the internet domain using TCP 
    The port number is passed as an argument */ 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

void error(const char *msg) 
{ 
    perror(msg); 
    exit(1); 
} 

int main(int argc, char *argv[]) 
{ 
    int sockfd, newsockfd, portno; 
    socklen_t clilen; 
    char buffer[1024]; 
    struct sockaddr_in serv_addr, cli_addr; 
    int n, total; 
    if (argc < 2) { 
     fprintf(stderr,"ERROR, no port provided\n"); 
     exit(1); 
    } 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd < 0) 
     error("ERROR opening socket"); 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    portno = atoi(argv[1]); 
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(portno); 
    if (bind(sockfd, (struct sockaddr *) &serv_addr, 
      sizeof(serv_addr)) < 0) 
     error("ERROR on binding"); 
    listen(sockfd,5); 
    clilen = sizeof(cli_addr); 
    newsockfd = accept(sockfd, 
       (struct sockaddr *) &cli_addr, 
       &clilen); 
    if (newsockfd < 0) 
     error("ERROR on accept"); 
    memset(buffer, '0xAB', sizeof(buffer)); 
    total = 0; 
    for (;;) { 
     n = write(newsockfd, buffer, sizeof(buffer)); 
     if (n < 0) 
      error("ERROR writing to socket"); 
     else 
      total += n; 
      printf("wrote %d/%d\n", n, total); 
    } 
    close(newsockfd); 
    close(sockfd); 
    return 0; 
} 

client.c:

/* client.c */ 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 

void error(const char *msg) 
{ 
    perror(msg); 
    exit(0); 
} 

int main(int argc, char *argv[]) 
{ 
    fd_set set; 
    int sockfd, portno, n, total, rv; 
    struct sockaddr_in serv_addr; 
    struct hostent *server; 
    struct timeval timeout; 

    char buffer[256]; 
    if (argc < 3) { 
     fprintf(stderr,"usage %s hostname port\n", argv[0]); 
     exit(0); 
    } 
    portno = atoi(argv[2]); 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd < 0) 
     error("ERROR opening socket"); 
    server = gethostbyname(argv[1]); 
    if (server == NULL) { 
     fprintf(stderr,"ERROR, no such host\n"); 
     exit(0); 
    } 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    bcopy((char *)server->h_addr, 
     (char *)&serv_addr.sin_addr.s_addr, 
     server->h_length); 
    serv_addr.sin_port = htons(portno); 
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
     error("ERROR connecting"); 
    bzero(buffer, 256); 

    FD_ZERO(&set); 
    FD_SET(sockfd, &set); 

    sleep(1); 

    timeout.tv_sec = 1; 
    timeout.tv_usec = 0; 
    total = 0; 
    for (;;) { 
     rv = select(sockfd + 1, &set, NULL, NULL, &timeout); 
     if (rv == -1) { 
      perror("select\n"); 
     } else if(rv == 0) { 
      printf("timeout\n"); 
      break; 
     } else { 
      n = read(sockfd, buffer, 256); 
      if (n < 0) 
      error("ERROR reading from socket"); 
      total += n; 
      printf("read %d/%d\n", n, total); 
     } 
    } 
    close(sockfd); 
    return 0; 
} 

Эти программы и взяты непосредственно из http://www.linuxhowtos.org/C_C++/socket.htm с модификацией, чтобы сообщить дополнительную статистику и заставить срываться.

Вот скриншот из Wireshark демонстрации TCP Window восстанавливающий 0 и налипания:

TCP Zero Window in Wireshark

Моя текущая теория в том, что есть какая-то ошибка в сетевом стеке на стороне VMWare на клиент, но это сложно сказать. До сих пор я пытался использовать три разных виртуальных сетевых интерфейса (e1000, e1000e, vlance) и по-прежнему имел одну и ту же проблему с каждым из них.

Я попытаюсь попробовать различные варианты vmx, чтобы уменьшить вероятность возникновения проблемы, но это, очевидно, убийца для стабильной системы, и мой прецедент (виртуализированные подчиненные Jenkins для CI) просто не позволит такого рода ошибка.

Я отчитаю, если смогу узнать что-нибудь новое.

EDIT: Я отправил ошибку в доску VMWare Community: https://communities.vmware.com/message/2648727

EDIT снова: Они зафиксировали его в VMware Fusion 8.5.7! См. Ту же ссылку, что и выше.