Возможно ли связать и прослушать несколько портов в Linux в одном приложении?Слушайте несколько портов с одного сервера
ответ
Для каждого порта, который вы хотите слушать, вы:
- Создать отдельную розетку с
socket
. - Привяжите его к соответствующему порту с помощью
bind
. - Вызовите
listen
на сокет, чтобы он был настроен с помощью очереди прослушивания.
В этот момент ваша программа прослушивает несколько сокетов. Чтобы принимать соединения на этих сокетах, вам нужно знать, к какому сокету подключается клиент. Вот где входит select
.Как это происходит, у меня есть код, который делает именно это сидение, так что вот полный проверенный пример ожидания соединений в нескольких сокетах и возврата файлового дескриптора соединения. Удаленный адрес возвращается в дополнительных параметрах (буфер должен быть предоставлен вызывающим абонентом, как и accept).
(socket_type
здесь является ЬурейеЕ для int
на системах Linux и INVALID_SOCKET
является -1
. Это там, потому что этот код был перенесен на Windows, а также.)
socket_type
network_accept_any(socket_type fds[], unsigned int count,
struct sockaddr *addr, socklen_t *addrlen)
{
fd_set readfds;
socket_type maxfd, fd;
unsigned int i;
int status;
FD_ZERO(&readfds);
maxfd = -1;
for (i = 0; i < count; i++) {
FD_SET(fds[i], &readfds);
if (fds[i] > maxfd)
maxfd = fds[i];
}
status = select(maxfd + 1, &readfds, NULL, NULL, NULL);
if (status < 0)
return INVALID_SOCKET;
fd = INVALID_SOCKET;
for (i = 0; i < count; i++)
if (FD_ISSET(fds[i], &readfds)) {
fd = fds[i];
break;
}
if (fd == INVALID_SOCKET)
return INVALID_SOCKET;
else
return accept(fd, addr, addrlen);
}
Этот код не говорит вызывающий, к которому подключен клиент, но вы можете легко добавить параметр int *
, который получит файловый дескриптор, который видел входящее соединение.
Мне было интересно, может ли это произойти без выбора/опроса, но, вероятно, нет. – Nick
Вы только bind()
к одной розетке, а затем listen()
и accept()
- сокет для привязки для сервера, файловый дескриптор из accept()
для клиента. Вы делаете свой выбор на последнем, ищем какой-либо клиентский сокет, на котором есть данные, ожидающие ввода.
Кстати, вы удалили свой ответ на мой вопрос или сделали мод? Вид сумасшедшего, что они сделали, если да, то прилагаемые комментарии были полезной информацией, которую мог использовать кто-то другой. –
nope ... был не мной. Я думал, что это был довольно хороший разговор. : -/ –
да, это было полезно, даже знать, что не работает ... моды здесь сумасшедшие; возможно, вы можете отредактировать его, чтобы включить некоторые из наших обсуждений и попросить его восстановить? вы могли бы даже сказать, что мы пробовали все это, и что делать магическое число - лучшая альтернатива всему этому, так что это был бы законный ответ, который я мог бы принять (так как это похоже на реальный ответ) к вам, я не против, в любом случае. Я, вероятно, просто собирался написать свой собственный ответ в любом случае, потому что тот, который был дан до сих пор, действительно не затрагивает мою проблему. –
В такой ситуации вас может заинтересовать libevent. Он сделает работу select()
для вас, возможно, используя гораздо лучший интерфейс, такой как epoll()
.
Огромный недостаток select()
является использование FD_...
макросов, которые ограничивают число сокета до максимального количества битов в fd_set
переменной (приблизительно от 100 до 256). Если у вас небольшой сервер с 2 или 3 подключениями, все будет в порядке. Если вы намереваетесь работать на гораздо большем сервере, то fd_set
может легко переполняться.
Кроме того, использование select()
или poll()
позволяет избежать темы на сервере (например, вы можете poll()
ваш сокет и знаете ли вы можете accept()
, read()
или write()
к ним.)
Но если вы действительно хотите сделать это как Unix, тогда вы хотите рассмотреть fork()
-ing перед тем, как позвонить accept()
. В этом случае вам абсолютно не нужны select()
или poll()
(если вы не слушаете много IP-адресов/портов и хотите, чтобы все дети могли отвечать на любые входящие соединения, но у вас есть недостатки с этими ...ядро может отправить вам другой запрос, пока вы уже обрабатываете запрос, тогда как только с accept()
ядро знает, что вы заняты, если не в самом вызове accept()
- ну, это не работает именно так, но как пользователь, это так, как это работает для вас.)
с fork()
вы готовите гнездо в главном процессе, а затем вызвать handle_request()
в дочернем процессе, чтобы вызвать функцию accept()
. Таким образом, у вас может быть любое количество портов и один или несколько детей для прослушивания каждого из них. Это самый лучший способ действительно очень быстро реагировать на любые входящие соединения под Linux (т.е. как пользователь и до тех пор, пока у вас есть дочерние процессы ждут клиента, это происходит мгновенно.)
void init_server(int port)
{
int server_socket = socket();
bind(server_socket, ...port...);
listen(server_socket);
for(int c = 0; c < 10; ++c)
{
pid_t child_pid = fork();
if(child_pid == 0)
{
// here we are in a child
handle_request(server_socket);
}
}
// WARNING: this loop cannot be here, since it is blocking...
// you will want to wait and see which child died and
// create a new child for the same `server_socket`...
// but this loop should get you started
for(;;)
{
// wait on children death (you'll need to do things with SIGCHLD too)
// and create a new children as they die...
wait(...);
pid_t child_pid = fork();
if(child_pid == 0)
{
handle_request(server_socket);
}
}
}
void handle_request(int server_socket)
{
// here child blocks until a connection arrives on 'server_socket'
int client_socket = accept(server_socket, ...);
...handle the request...
exit(0);
}
int create_servers()
{
init_server(80); // create a connection on port 80
init_server(443); // create a connection on port 443
}
Обратите внимание, что функция handle_request()
показан здесь как обработка одного запроса. Преимущество обработки одного запроса состоит в том, что вы можете сделать это способом Unix: распределите ресурсы по мере необходимости и после ответа на запрос, exit(0)
. exit(0)
позвонит вам close()
, free()
и т. Д.
В отличие от этого, если вы хотите обрабатывать несколько запросов в строке, вы должны убедиться, что ресурсы освобождены до того, как вы вернетесь к вызову accept()
. Кроме того, функция sbrk()
в значительной степени никогда не будет призвана уменьшить объем памяти вашего ребенка. Это означает, что время от времени оно будет расти немного. Вот почему сервер, такой как Apache2, настроен на то, чтобы ответить на определенное количество запросов на каждого ребенка до начала нового ребенка (по умолчанию он составляет от 100 до 1000 в эти дни.)
- 1. Слушайте несколько портов для сервера сокетов
- 2. Слушайте несколько портов за раз, используя Node.JS
- 3. Слушайте ряд портов UDP
- 4. Слушайте разговор, используя переадресацию портов
- 5. Netty: Слушайте несколько адресов/портов с одним ServerBootstrap
- 6. Слушайте 2 последовательных портов одновременно
- 7. Несколько портов сервера развития asp.net
- 8. Слушайте более одного KeyphraseSearch
- 9. Несколько портов, прослушивающих laravel
- 10. Несколько URL-адресов для одного хоста с отображением портов?
- 11. несколько портов UDP
- 12. Слушайте NSNotification с одного глобального места
- 13. Слушайте изменения событий iCal с сервера
- 14. Несколько портов и потоки
- 15. Collectd - несколько портов JMX
- 16. Слушайте несколько ответов, полученных одним HTTP-запросом
- 17. Слушайте Javascript несколько анимаций CSS
- 18. Несколько потоков для нескольких портов?
- 19. Несколько портов http Amazon
- 20. Слушайте несколько кликов по ссылке с JQuery
- 21. Несколько портов для одного приложения в плавких предохранителях jboss
- 22. Лучший способ передачи открывающего HTTP-сервера python на несколько портов
- 23. Все прослушиватели портов сервера с php
- 24. Служба WCF, слушая несколько портов
- 25. Как прослушивать несколько последовательных портов с C#
- 26. Получение портов клиентов из конфигурационного сервера
- 27. Слушайте изменения ресурсов Календаря Google без сервера
- 28. Несколько JVMs против сервера одного приложения
- 29. анзибль несколько хостов с переназначение портов
- 30. Как связать несколько портов с помощью AsynchronousServerSocketChannel?
да, что возможно, вам нужно использовать ' select' или threads, хотя – perreal
Да. Лучшим ответом на эти вопросы является то, что вы должны написать небольшое тестовое приложение и * попробовать сами *. По мере того, как вы становитесь более опытными, вы обнаружите, что чаще всего пишите эти маленькие «тестовые программы», чтобы понять, что происходит. –
Как можно выбрать? Я не уверен, как сделать много привязок для одного сокета. – user2175831