Они исправлены в 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 и налипания:
Моя текущая теория в том, что есть какая-то ошибка в сетевом стеке на стороне VMWare на клиент, но это сложно сказать. До сих пор я пытался использовать три разных виртуальных сетевых интерфейса (e1000, e1000e, vlance) и по-прежнему имел одну и ту же проблему с каждым из них.
Я попытаюсь попробовать различные варианты vmx, чтобы уменьшить вероятность возникновения проблемы, но это, очевидно, убийца для стабильной системы, и мой прецедент (виртуализированные подчиненные Jenkins для CI) просто не позволит такого рода ошибка.
Я отчитаю, если смогу узнать что-нибудь новое.
EDIT: Я отправил ошибку в доску VMWare Community: https://communities.vmware.com/message/2648727
EDIT снова: Они зафиксировали его в VMware Fusion 8.5.7! См. Ту же ссылку, что и выше.
Вы пытались удалить 'timeout = 10' и посмотреть, обрабатывается ли запрошенный URL-адрес в течение периода ожидания по умолчанию? – Eduard
@EduardDaduya. Если я удалю таймаут, поток застрянет навсегда. –
Мои извинения, я неправильно понял проблему, вы извлекаете данные через urlopen успешно, но чтение извлеченных данных повышает указанное исключение. Что-то, с чем я еще не сталкивался. Я считаю, что это объяснение поможет вам с вашей текущей проблемой. Http://stackoverflow.com/a/26765074/1809168 – Eduard