LINUX.ORG.RU

Ответ на: комментарий от nanoolinux

я наверное что-то не понимаю... как вообще может быть на одной машине больше 65536 открытых сокетов?

quest ★★★★
() автор топика
Ответ на: комментарий от quest

открытый сокет это не порт+айпи. Это айпи+порт на одной стороне + айпи+порт на другой. Т.е. это комбинация четырёх чисел, а не двух.

Но это только для ipv4 сокетов. Если брать юникс сокеты, то там грубо говоря всё ограничено только ресурсами ядра.

nanoolinux ★★★★
()
Последнее исправление: nanoolinux (всего исправлений: 1)
Ответ на: комментарий от quest

Можно и на одном IP. Если ты слушаешь сокет и к тебе подсоединилось 100000 клиентов, с твой стороны это 100000 сокетов не только на одном IP но и на одном порту.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

сколько максимально открывали на одном ip, что крутили для этого и где об этом почитать?

quest ★★★★
() автор топика
Ответ на: комментарий от slovazap

Ничего не надо крутить. Я же сказал, на слушающей стороне используется только один порт.

Да положим на сервере один ip и один порт, но при соединении на сервере создается сокет этого соединения. Вот это почитай:

количество исходящих TCP соединений

Приведи пример как это обойти.

quest ★★★★
() автор топика
Ответ на: комментарий от quest

Ещё раз повторяю: количество сокетов ограничено только ресурсами системы и никак не связано с ограничением количества портов. На сервере используется _один_ порт, поэтому его эта проблема не касается и на нём будет создаваться столько сокетов, сколько хватит памяти. На клиентах, понятное дело, нужно тюнить диапазоны портов и/или использовать разные адреса.

slovazap ★★★★★
()
Ответ на: комментарий от quest

как вообще может быть на одной машине больше 65536 открытых сокетов?

порты никакого отношения к сокетам не имеют. Разве что слушать ты можешь не больше 65536 сокетов, ибо если один порт слушать двумя сокетами(сразу), получится ерунда.

emulek
()
Ответ на: комментарий от quest

но при соединении на сервере создается сокет этого соединения.

это уже после соединения.

emulek
()
Ответ на: комментарий от slovazap

положим есть сервер и есть миллион клиентов, каждый клиент ломится на один и тот же ip сервера, на один и тот же порт и устанавливает одно соединение. Но сервер когда делать accept() порождает новый сокет на каждое новое соединение, так вот упирается сервер в потолок. sysctl net.ipv4.ip_local_port_range помогает поднять потолок выше. но все одно это не миллион соединений. как сделать миллион на одном IP:PORT?

память свободная есть, ulimit поднят на файлы и память.

quest ★★★★
() автор топика
Ответ на: комментарий от slovazap

количество pid например в системе всего 32767, хотя вроде и можно вкомпилить где-то в ядре чтобы больше

quest ★★★★
() автор топика
Ответ на: комментарий от emulek

насколько я помню новые соединения просто не проходят и все. это давно был старый тест, буду писать новый

quest ★★★★
() автор топика
Ответ на: комментарий от quest

Но сервер когда делать accept() порождает новый сокет на каждое новое соединение, так вот упирается сервер в потолок. sysctl net.ipv4.ip_local_port_range помогает поднять потолок выше

Нет.

slovazap ★★★★★
()
Ответ на: комментарий от quest

насколько я помню новые соединения просто не проходят и все. это давно был старый тест, буду писать новый

давай код, посмотрим...

emulek
()
Ответ на: комментарий от slovazap

Нет.

man accept

«Эта функция извлекает первый запрос на соединение из очереди ожидающих соединений, создаёт новый подключенный сокет»

quest ★★★★
() автор топика
Ответ на: комментарий от emulek
$ cat server.cpp 
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>

int main()
{
        int rc;


        rc = socket(AF_INET, SOCK_STREAM, 0);
        if (rc == -1)
        {
                printf("error socket: %s\n", strerror(errno));
                return 1;
        }
        int sock = rc;


        sockaddr_in addr;
        addr.sin_family      = AF_INET;
        addr.sin_port        = htons(30000);
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");


        rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
        if (rc == -1)
        {
                printf("error bind: %s\n", strerror(errno));
                return 1;
        }


        rc = listen(sock, 1024);
        if (rc == -1)
        {
                printf("error listen: %s\n", strerror(errno));
                return 1;
        }


        uint64_t count = 1;
        for (;;)
        {
                rc = accept(sock, NULL, NULL);
                if (rc == -1)
                {
                        printf("error accept: %s\n", strerror(errno));
                        return 1;
                }

                printf("server count:%lu\n", count++);
        }


        return 0;
}
$ cat client.cpp 
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>

int main()
{
        int rc;


        uint64_t count = 1;
        for (;;)
        {
                rc = socket(AF_INET, SOCK_STREAM, 0);
                if (rc == -1)
                {
                        printf("error socket: %s\n", strerror(errno));
                        return 1;
                }
                int sock = rc;


                sockaddr_in addr;
                addr.sin_family      = AF_INET;
                addr.sin_port        = htons(30000);
                addr.sin_addr.s_addr = inet_addr("127.0.0.1");


                rc = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
                if (rc == -1)
                {
                        printf("error connect: %s\n", strerror(errno));
                        break;
                }

                printf("client count:%lu\n", count++);
        }


        pause();


        return 0;
}

подправьте ip/port, сделайте ulimit -n 1000000, запустите server и натравите на него один или несколько client с одной или нескольких машин и добейтесь миллиона открытых соединений на сервере...

quest ★★★★
() автор топика
Ответ на: комментарий от quest

А что у тебя не получается конкретно, в каком месте затык?

edigaryev ★★★★★
()
Ответ на: комментарий от quest

Выставляем /proc/sys/fs/file-max, потом ulimit -Hn с ulimit -Sn, в сервере привязываем по INADDR_ANY и тогда даже с одной машины клиентами можно подключаться по любым адресам интерфейсов (то есть по 127.*.*.* при маске 255.0.0.0 на lo, по любым его aliasам (lo:1, lo:2, ... с соответствующими IP) и т.д. для других интерфейсов) — каждый клиент количество портов исчерпывает, но на сервере соединений может быть сколько угодно (можно /proc/sys/net/ipv4/ip_local_port_range сделать совсем небольшим — не важно).

Вообще соединение это (адрес1, порт1, адрес2, порт2) — сервер берёт адрес1 и порт1, в простом случае клиенты на той же машине берут тот же адрес2 и исчерпывают порты в порт2, так что может показаться то что тебе кажется, но на самом деле ведь есть ещё адрес2 — локально его можно варьировать (как с INADDR_ANY), ну а нормально при разных машинах он будет и так разным.

В случае TCP такое соединение это и есть сокет (http://en.wikipedia.org/wiki/Network_socket#Socket_pairs).

quasimoto ★★★★
()
Ответ на: комментарий от quest

как сделать миллион на одном IP:PORT

пойми простой момент, для идентификации соединения используется не пара IP:PORT, а четвёрка LOCAL_IP:LOCAL_PORT:REMOTE_IP:REMOTE_PORT

поэтому для одного ip и одного порта ты можешь открыть сколько угодно соединений от разных клиентов, хоть миллион (хотя наверное конечно есть какое то ограничение, может там я не знаю int 32-разрядный или ещё что.. но это точно не 65к, а сильно больше).

AndreyKl ★★★★★
()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от quasimoto

локально его можно варьировать (как с INADDR_ANY)

То есть адрес сервера при INADDR_ANY может варьироваться. А адрес клиента можно прямо с помощью bind присваивать если на интерфейсе(ах) есть что. Например:

// c.cc

#include <cstring>
#include <cerrno>

#include <string>
#include <iostream>

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

#define CHECK(call) \
    if ((call) == -1) throw std::string(strerror(errno));

int main(int, char **argv) {

    try {

        for (size_t count = 1;; ++count) {

            int sock;
            CHECK(sock = socket(AF_INET, SOCK_STREAM, 0));

            sockaddr_in laddr;
            laddr.sin_family = AF_INET;
            laddr.sin_addr.s_addr = inet_addr(argv[1]);
            laddr.sin_port = 0;
            CHECK(bind(sock, (sockaddr*)&laddr, sizeof laddr));

            sockaddr_in raddr;
            raddr.sin_family = AF_INET;
            raddr.sin_port = htons(30000);
            raddr.sin_addr.s_addr = inet_addr(argv[2]);
            CHECK(connect(sock, (sockaddr*)&raddr, sizeof raddr));

            std::cout << '[' << getpid() << ']'
                      << " client count: " << count << std::endl;

        }

    } catch (std::string const& error) {

        std::cout << error << std::endl;

    }

}
// s.cc

#include <cstring>
#include <cerrno>

#include <string>
#include <iostream>

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

#define CHECK(call) \
    if ((call) == -1) throw std::string(strerror(errno));

int main() {

    try {

        int sock;
        CHECK(sock = socket(AF_INET, SOCK_STREAM, 0));

        int optval = 1;
        CHECK(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval));

        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(30000);
        addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // htonl(INADDR_ANY);
        CHECK(bind(sock, (sockaddr*)&addr, sizeof addr));

        CHECK(listen(sock, 1024));

        for (size_t count = 1;; ++count) {
            CHECK(accept(sock, 0, 0));
            std::cout << "server count: " << count << std::endl;
        }

    } catch (std::string const& error) {

        std::cout << error << std::endl;

    }

}
# echo 1000000 > /proc/sys/fs/file-max
# ulimit -Hn 1000000; ulimit -Sn 1000000
# c++ c.cc -o c; c++ s.cc -o s
[1] # ./c 127.0.0.1 127.0.0.1 & ./c 127.0.0.2 127.0.0.1 &./c 127.0.0.3 127.0.0.1 &./c 127.0.0.4 127.0.0.1 &./c 127.0.0.5 127.0.0.1 & ./c 127.0.0.6 127.0.0.1 & ./c 127.0.0.7 127.0.0.1 &./c 127.0.0.8 127.0.0.1 &./c 127.0.0.9 127.0.0.1 &./c 127.0.0.10 127.0.0.1 &
...
[5421] client count: 28072
[5418] client count: 28233
Address already in use
[5421] client count: 28073
[5421] client count: 28233
Address already in use

[1]   Done                    ./c 127.0.0.1 127.0.0.1
[2]   Done                    ./c 127.0.0.2 127.0.0.1
[3]   Done                    ./c 127.0.0.3 127.0.0.1
[4]   Done                    ./c 127.0.0.4 127.0.0.1
[5]   Done                    ./c 127.0.0.5 127.0.0.1
[6]   Done                    ./c 127.0.0.6 127.0.0.1
[7]   Done                    ./c 127.0.0.7 127.0.0.1
[8]   Done                    ./c 127.0.0.8 127.0.0.1
[9]-  Done                    ./c 127.0.0.9 127.0.0.1
[10]+  Done                    ./c 127.0.0.10 127.0.0.1
[2] # ./s
...
server count: 282328
server count: 282329
server count: 282330
^C

На каждом из параллельных клиентов на своих адресах (что их отличает) < 65K, на сервере — больше.

quasimoto ★★★★
()
Ответ на: комментарий от quest

Если не введено дополнительных ограничений (типа maxfiles) то никак не надо - примет из коробки.

slovazap ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.