предел количества соединений TCP в Win2K Pro

Тема в разделе "WASM.NETWORKS", создана пользователем monobo, 1 авг 2005.

  1. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    Столкнулся с тем, что на моей машине Win2K Pro SP4 существует некий предел на количество TCP соединений. Возможно и UDP тоже. Проявляется он, например, в том, что при частых обновлениях окна браузера (IE6SP1, Firefox 1.0.6) в некоторый момент соединение перестаёт устанавливаться. Этот предел, возможно, где-то около 64000(?) соединений - несколько часов интенсивного обновления браузера. Но, проявляется этот предел не только при использовании браузера, а и, скажем, eMule Plus, который за пару суток работы доводит систему до такого же состояния.

    Telnet www.google.com 80 пишет "Could not open a connection to host on port 80 : Connect failed". В то же время ICMP (ping, traceroute) проходят без проблем.

    Netstat -an показывает штук двадцать обычных соединений.

    Лечится это только перезагрузкой.

    Всякие там файрволы и прочее не влияют, ибо их я отключал полностью, менял на другие и т.д. -- проблема ровно та же самая.

    Доступ в инет по ADSL модем Zyxel 630C.



    Возможно, это как-то связано с количеством портов 64K ? Но netstat молчит. Да, и за несколько часов работы все таймауты на некорректно закрытые соединения должны истечь...

    В общем, если кто сталкивался с такой проблемой -- откликнитесь, плиз!

    Да, и вообще, любая помощь приветствуется.
     
  2. semen

    semen New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2004
    Сообщения:
    334
    Адрес:
    Russia
    monobo

    Хмм, я сталкивался, но только с проблемой частичного закрытия соединения(т.е. висит в состоянии TIME_WAIT)

    Но за пару часов-то все должно закрыться.

    Еще читал что-то про ограничение количества TCP соединений в XP, даже на патч какой-то линк был... а так хз.
     
  3. reverser

    reverser New Member

    Публикаций:
    0
    Регистрация:
    27 янв 2004
    Сообщения:
    615
  4. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    semen



    TIME_WAIT видно в netstat -an. У меня может вообще не быть TIME_WAIT в нем, но ни одно новое TCP/UDP соединение не устанавливается. Похоже на некий карман, которые забивается в системе... и высвобождается только при перезагрузке.



    reverser



    Да, похоже. Но imho совсем не то...
     
  5. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    monobo

    Вызывая функцию socket для появления INVALID_SOCKET, я получил порядка 70К сокетов, и половину пунктов меню в виде чёрных прямоугольников. С созданными сокетами я никаких операций вообще не проводил. У меня есть подозрение что их нужно удалять, не надеясь на MS, только вот в других моих экспериментах я никак не мог прибить сокеты зависшие на TIME_WAIT 8(
     
  6. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    Black_mirror

    Вот, похоже на то!

    Порядка 70К -- это может быть 64К -- ограничение на количество портов в IPv4. Есть подозрение, что в винде номера клиентских портов выдаются последовательно. Т.е. ... 13209, 13210, 13211...

    Так вот когда дело доходит до

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

    "MaxUserPort" ~= fffe

    То на этом винда считает свою миссию выполненной и блокирует создание клиентских сокетов.



    Страное какое-то поведение... Непонятно где рыть.
     
  7. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    monobo

    Я не открывал соединений, я только создавал сокеты. Номера портов вообще никак не фигурировали.
     
  8. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Читал, что все созданные сокеты надо закрывать самому. Винда этого не делает после закрытия программы.

    Но может ошибаюсь.



    P.S. Максимальное число сокетов можно посмотреть в WSAData.
     
  9. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    rmn



    А есть какая-нибудь тулзень, где можно посмотреть на ... тот самый карман, который заполняется и не освобождается :)

    Скажем, на процесс создания сокета.

    Оттрассировать бы как-нибудь это дело. Ну, не софтайсом же его ковырять?

    К примеру, есть идея, что когда номер клиентского порта достигает 64К-1, то дальнейшая выдача клиентских портов прекращается. Как это можно отследить?
     
  10. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"


    И с этим ничего не поделать, так как число портов считается вордами, и за предел 64К выйти не может.





    При закрытии сокета все освобождается, никаких утечек я тут не замечал.





    Что такое сокет? Это всего-лишь хэндл устройства \Device\Afd, а все открытые хэндлы при завершении процесса автоматом закрываются.
     
  11. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Не знаю как на счет 64К-1 - в PSDK пишут, что номера клиентских портов выделяются в диапазоне 1024-5000.

    У меня максимальное число сокетов - 32767 (w2k sp4).



    Процесс создания сокета можешь в ИДЕ посмотреть.
     
  12. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Этот процесс выглядит как открытие afd. Драйвер afd.sys (TDI клиент) просто выделит память под сокет, реальная работа с сокетом пойдет после connect или bind.



    При вызове bind afd открывает локальный адрес, а при вызове accept открывает точку подключения (\Device\Tcp) и посылает Irp пакет TDI_ASSOCIATE_ADDRESS, затем посылает TDI_LISTEN, который завершается только в момент подключения клиента, после чего подключение либо принимается либо отклоняется пакетом TDI_ACCEPT.



    При вызове connect происходит все тоже, за отличием того, что посылается TDI_CONNECT.
     
  13. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    Ms Rem



    Ну, вот сегодня я не выключаю комп и вижу, порты клиентских соединений у меня монотонно растут. Вот сейчас в нетстате оно 20755. Вот так вот примерно:

    TCP xxx.xxx.xxx.xxx:20733 84.122.146.60:4662 ESTABLISHED

    TCP xxx.xxx.xxx.xxx:20735 83.77.44.137:9210 TIME_WAIT

    TCP xxx.xxx.xxx.xxx:20741 80.36.36.151:4662 ESTABLISHED

    TCP xxx.xxx.xxx.xxx:20743 160.75.68.12:443 ESTABLISHED

    TCP xxx.xxx.xxx.xxx:20745 155.210.159.29:4662 ESTABLISHED

    TCP xxx.xxx.xxx.xxx:20751 193.95.248.17:4662 ESTABLISHED

    TCP xxx.xxx.xxx.xxx:20753 84.122.34.49:7777 ESTABLISHED

    TCP xxx.xxx.xxx.xxx:20755 81.32.98.131:4662 ESTABLISHED



    Так вот когда эти номера дорастут до 64К, по идее, они не сбросятся и не будут выдаваться снова, а весь процесс застопорится. Вот интересно, можно ли как-то узнать следующий номер клиентского порта; сбросить этот счетчик?



    rmn

    О, вот это уже вроде близко к теме!

    PSDK -- это что? Можно УРЛ?
     
  14. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
  15. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    Ms Rem



    Ух, хорошо! Вы не путаете серверный и клиентский порты? Или я чего-то не догоняю?..
     
  16. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    rmn





    Гхм... :) У меня есть полная MSDN July 2004 -- там не нашел. Можно поточнее ссылочку, если не трудно?
     
  17. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    monobo





    А между ними разница только в том, что для серверных сокетов локальный адрес биндится на нужный порт, а для клиентских - на любой свободный > 1024.

    Процесс создания сокета в любом случае одинаков, так как биндится локальный адрес и создается точка подключения.

    Если интересно, могу привести прблизительный код который это делает.
     
  18. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    Ms Rem

    Спасибо за разъяснения!





    Интересно, приведите, плиз!
     
  19. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Вот код делающий connect, я из него правда кое-что выкинул, но общая суть должна быть понятна :)


    Код (Text):
    1. int connect(SOCKET s, SOCK_ADDR* name, int namelen)
    2. {
    3.     NTSTATUS                         status;   
    4.     PSocketData sdata = (PSocketData)s;
    5.     TSocketData                      Transport;
    6.     TA_IP_ADDRESS                    Addr;
    7.     TDI_CONNECTION_INFORMATION       tdc = { 0 };
    8.     PIRP                             Irp;
    9.    
    10.     InitIPAddress(&Transport.RemoteAddress, INADDR_ANY, 0);
    11.     Transport.Type = SOCK_STREAM;
    12.     sdata->Type    = SOCK_STREAM;
    13.  
    14.     status = OpenTransportAddress(&Transport, (PTRANSPORT_ADDRESS)&Transport.RemoteAddress);
    15.  
    16.     status = OpenConnectionEndpoint(sdata, sdata);
    17.  
    18.     sdata->SecondFileHandle = Transport.FileHandle;
    19.     sdata->SecondFileObject = Transport.FileObject;
    20.     sdata->DeviceObject = IoGetRelatedDeviceObject(sdata->FileObject);
    21.  
    22.     Irp = IoAllocateIrp(sdata->DeviceObject->StackSize, FALSE);
    23.  
    24.     TdiBuildAssociateAddress(Irp, sdata->DeviceObject,
    25.                              sdata->FileObject,
    26.                              IrpCompletionRoutune, sdata,
    27.                              Transport.FileHandle);
    28.     status = IoCallDriver(sdata->DeviceObject, Irp);
    29.  
    30.     if (status == STATUS_PENDING)
    31.     {
    32.         KeWaitForSingleObject(&sdata->SyncEvent, Executive, KernelMode, FALSE, NULL);
    33.         status = Irp->IoStatus.Status;
    34.     }
    35.  
    36.     KeClearEvent(&sdata->SyncEvent);
    37.  
    38.     Addr.TAAddressCount = 1;
    39.     Addr.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
    40.     Addr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
    41.     Addr.Address[0].Address[0].sin_port = ((PSOCKADDR_IN)name)->sin_port;
    42.     Addr.Address[0].Address[0].in_addr  = ((PSOCKADDR_IN)name)->sin_addr.S_un_l;
    43.     tdc.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
    44.     tdc.RemoteAddress = &Addr;
    45.  
    46.     TdiBuildConnect(Irp, sdata->DeviceObject,
    47.                     sdata->FileObject,
    48.                     IrpCompletionRoutune, sdata,
    49.                     NULL, &tdc, NULL);
    50.                        
    51.     status = IoCallDriver(sdata->DeviceObject, Irp);
    52.  
    53.     if (status == STATUS_PENDING)
    54.     {
    55.         KeWaitForSingleObject(&sdata->SyncEvent, Executive, KernelMode, FALSE, NULL);
    56.         status = Irp->IoStatus.Status;
    57.     }
    58.     KeClearEvent(&sdata->SyncEvent);
    59.  
    60.     IoFreeIrp(Irp);
    61.     return 0;
    62. }




    Открытие локального адреса и точки подключения выглядит так:
    Код (Text):
    1.    switch (sdata->Type)
    2.     {
    3.         case SOCK_STREAM :
    4.           sDeviceName = L"\\Device\\Tcp";
    5.           .....
    6.  
    7.     RtlInitUnicodeString(&uDeviceName, sDeviceName);
    8.  
    9.     InitializeObjectAttributes(&Attr, &uDeviceName,
    10.                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
    11.                                NULL,
    12.                                NULL);
    13.  
    14.     TransportAddressLength = GetTransportAddressLength(pTransportAddress);
    15.  
    16.     status = BuildEaBuffer(TDI_TRANSPORT_ADDRESS_LENGTH, TdiTransportAddress,          
    17.                            TransportAddressLength, pTransportAddress,
    18.                            &pTransportAddressEa, &TransportEaBufferLength);
    19.  
    20.     status = ZwCreateFile(&sdata->FileHandle,
    21.                           GENERIC_READ | GENERIC_WRITE,
    22.                           &Attr,
    23.                           &IoStatus,
    24.                           NULL,
    25.                           FILE_ATTRIBUTE_NORMAL,                             
    26.                           FILE_SHARE_READ | FILE_SHARE_WRITE,
    27.                           FILE_OPEN,
    28.                           0,
    29.                           pTransportAddressEa,                        
    30.                           TransportEaBufferLength);
    31.  
    32.     ExFreePool(pTransportAddressEa);
    33.  
    34.     status = ObReferenceObjectByHandle(sdata->FileHandle,
    35.                                            0,
    36.                                            0,
    37.                                            KernelMode,
    38.                                            &sdata->FileObject,
    39.                                            NULL);
    40.  
    41.     sdata->DeviceObject = IoGetRelatedDeviceObject(sdata->FileObject);




    Само создание сокета не привожу, так как это просто выделение памяти и заполнение структур.
     
  20. monobo

    monobo New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    14
    Ms Rem

    Спасибо! Попробую врубиться.

    А не выскажете ещё идей -- где там может быть затык? Куда копать?