Даже ИИСУС не мучал себя так. Создание неблокирующего сокета и ожидание входящих соединений с использованием функции poll(). Вдруг поможет Code (Text): section .data server equ 0 client equ 1 buffer equ 2 addr equ 3 addrLen equ 4 pollset equ 5 pollsetSize equ 6 k_maxClients equ 128 section .text global _start _start: ; Создаём неблокирующий сокет, использующий протокол TCP mov eax, 41 mov ebx, 1 mov ecx, 6 xor edx, edx int 0x80 mov ebx, eax mov eax, 102 xor ecx, ecx xor edx, edx mov esi, 65533 int 0x80 ; Задаём сокету порт 65533 mov eax, 49 mov ebx, 1 xor ecx, ecx mov dx, 65533 push ecx push dx push ebx mov ecx, esp mov edx, 16 int 0x80 ; Создаём очередь входящих пакетов mov eax, 50 mov ebx, 1 mov ecx, 512 int 0x80 ; Резервируем список объектов для poll'a mov dword [pollsetSize], 1 listen_loop: ; Ждём бесконечно, пока один из объектов в поллсете не просигналит mov eax, 52 mov ebx, [pollset] mov ecx, [pollsetSize] mov edx, -1 int 0x80 ; Пройдёмся по всему поллсету и найдём того, кто просигналил mov ebx, 0 mov esi, [pollsetSize] mov edi, pollset poll_loop: cmp ebx, esi jge listen_loop_end ; Смотрим, какой объект просигналил mov eax, [edi + ebx * 8] test byte [eax + 1], 1 jz poll_next ; Сбрасываем маску событий mov byte [eax + 1], 0 ; Обработка серверного сокета cmp ebx, 0 jne client_data ; На сервер пришёл новый клиент, принимаем его mov eax, 42 mov ebx, [server] mov ecx, addr mov edx, addrLen int 0x80 mov ebx, eax cmp [pollsetSize], k_maxClients jg client_disconnect ; Добавляем клиента в поллсет mov eax, ebx mov ebx, [pollsetSize] mov edi, pollset shl ebx, 3 add edi, ebx mov [edi], eax mov byte [edi + 1], 1 inc dword [pollsetSize] jmp poll_next client_data: ; Клиент прислал данные, читаем mov eax, 45 mov ebx, [eax + ebx * 8] mov ecx, buffer mov edx, 65536 xor esi, esi int 0x80 ; ... Теперь у нас данные в buffer, можно с ними работать ... jmp poll_next client_disconnect: ; Мы упёрлись в лимит клиентов, отключаем клиента mov eax, 6 mov ebx, [client] xor ecx, ecx int 0x80 poll_next: inc ebx jmp poll_loop listen_loop_end: ; Завершение программы mov eax, 1 xor ebx, ebx int 0x80 --- Сообщение объединено, Oct 28, 2023 --- Code (Text): section .data fds: resb 0 fds_len: dd 0 FDS_ARRAY_CHUNK_SIZE equ 100 MAX_MESSAGE_LEN equ 1728 do_linemode db 255, 253, 34 on_linemode db 255, 250, 34, 1, 1, 255, 240 will_echo db 255, 253, 1 wont_echo db 255, 252, 1 reply_buff db 512 dup(0) section .text global _start _start: ; Initialize fds and fds_len mov eax, 0 mov fds_len, eax ; Set stdout to unbuffered mode xor eax, eax mov [stdout], eax ; Check if host and port are provided cmp dword [argc], 3 jne error ; Create socket xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 2 mov bl, 1 mov ecx, 0 int 0x80 mov servfd, eax ; Set server address xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 2 mov bl, 1 mov ecx, 0 int 0x80 mov servaddr.sin_family, ax mov servaddr.sin_addr.s_addr, ebx mov servaddr.sin_port, cx ; Bind socket xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 2 mov bl, 2 mov ecx, 0 int 0x80 ; Listen for connections xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 2 mov bl, 4 mov ecx, 1024 int 0x80 ; Set socket to non-blocking mode xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 54 mov bl, 2 mov ecx, 1 int 0x80 ; Add server socket to fds mov eax, servfd call fds_set ; Start main loop main_loop: ; Poll for events xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 1 mov ebx, fds mov ecx, fds_len mov edx, 100 int 0x80 mov pollret, eax ; Process events xor eax, eax xor ebx, ebx xor ecx, ecx mov ecx, fds_len mov ebx, fds process_events_loop: cmp eax, ecx jge main_loop_end ; Check if fd is valid mov edx, [ebx + eax * 8] cmp edx, 0 jle process_events_next ; Check if POLLIN event is set mov edx, [ebx + eax * 8 + 4] and edx, 1 jz process_events_next ; Check if fd is server socket cmp edx, servfd je process_events_accept ; Read message from client xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 3 mov ebx, edx mov ecx, buff mov edx, MAX_MESSAGE_LEN int 0x80 ; Replace commands with spaces xor eax, eax xor ebx, ebx xor ecx, ecx mov ecx, eax replace_commands_loop: cmp ecx, edx jge process_events_send_to_all mov bl, [ebx + ecx] cmp bl, 0 je replace_commands_end cmp bl, ' ' jl replace_commands_space cmp bl, 126 jg replace_commands_space jmp replace_commands_next replace_commands_space: mov bl, ' ' replace_commands_next: mov [ebx + ecx], bl inc ecx jmp replace_commands_loop replace_commands_end: ; Send message to all clients process_events_send_to_all: xor eax, eax xor ebx, ebx xor ecx, ecx mov ecx, fds_len mov ebx, fds send_to_all_loop: cmp eax, ecx jge process_events_next mov edx, [ebx + eax * 8] cmp edx, 0 jle send_to_all_next cmp edx, servfd je send_to_all_next xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 4 mov ebx, edx mov ecx, buff mov edx, MAX_MESSAGE_LEN int 0x80 send_to_all_next: inc eax jmp send_to_all_loop ; Accept new connection process_events_accept: xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 5 mov ebx, servfd xor ecx, ecx xor edx, edx int 0x80 mov connfd, eax ; Perform telnet negotiation xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 6 mov ebx, connfd int 0x80 ; Add new client to fds mov eax, connfd call fds_set process_events_next: inc eax jmp process_events_loop main_loop_end: ; Exit program xor eax, eax xor ebx, ebx xor ecx, ecx int 0x80 error: ; Print error message xor eax, eax xor ebx, ebx xor ecx, ecx mov al, 4 mov ebx, 1 mov ecx, error_message mov edx, error_message_len int 0x80 ; Exit program xor eax, eax xor ebx, ebx xor ecx, ecx int 0x80 fds_set: ; Add fd to fds push ebp mov ebp, esp pushad mov eax, 0 mov ebx, fds_len fds_set_loop: cmp eax, ebx je fds_set_found mov edx, [fds + eax * 8] cmp edx, -1 jge fds_set_next mov [fds + eax * 8], ebp mov [fds + eax * 8 + 4], 1 jmp fds_set_end fds_set_next: inc eax jmp fds_set_loop fds_set_found: call extend_fds mov [fds + eax * 8], ebp mov [fds + eax * 8 + 4], 1 fds_set_end: popad pop ebp ret extend_fds: ; Extend fds array push ebp mov ebp, esp pushad mov eax, fds_len add eax, FDS_ARRAY_CHUNK_SIZE mov ebx, eax mov eax, fds push eax push ebx push 8 call realloc add esp, 12 xor eax, eax mov ebx, FDS_ARRAY_CHUNK_SIZE extend_fds_loop: cmp eax, ebx je extend_fds_end mov edx, [fds + fds_len * 8] mov [edx], -1 mov [edx + 4], 0 inc eax inc fds_len jmp extend_fds_loop extend_fds_end: popad pop ebp ret section .bss stdout resb 4 section .data error_message db "Please provide host and port. Example: telnet-chat 0.0.0.0 4022", 0 error_message_len equ $ - error_message
Спасибо что откликнулись! Но мне нужен читабельный код и x64, я буду выкладывать исходник сервера. С порядком вызовом функций ознакомлюсь, если получится
Ишь какой! Мы тебе напишем код, а ты его выложишь в паблик под своим авторством. А ловко ты это придумал!
Можно спросить по коду? Почему MAX_MESSAGE_LEN equ 1728 и reply_buff db 512 dup(0) имеют разные значения?
Выглядит, будто эти значения взяты с потолка. В TCP размер пакета и на приём, и на передачу не может быть больше 65535 байт.
Вот мне интересно, если портов всего 65535 (0 - не считаем), тогда как в вашей схеме уместятся 100к клиентских сокетов, каждому из которых надо выделить свободный порт?
зачем? все на один порт подключаются - серверный. для разных сервисов свои порты, днс, веб сервер и т.д.
Ваззапп делал 1М (1 миллион) TCP конектов еще 12 лет назад https://blog.whatsapp.com/1-million-is-so-2011 --- Сообщение объединено, Nov 4, 2023 --- TCP (v4): 32 бита сорс, 32 бита дест адресс 16 бит сорс 16 бит дест порт всего комбинаций 1 квадриллион https://prnt.sc/LdUgYNe67uIM
У принятых клиентов будет тот же локальный порт, что и у сервера, а remote-порты нас никак не ограничивают. Например, ты открыл порт :65533 Локальный адресУдалённый адрес127.0.0.1:65533-Сервер127.0.0.1:65533111.111.111.111:1234Клиент 1127.0.0.1:65533222.222.222.222:5678Клиент 2У всех клиентов одинаковый локальный порт. Можешь убедиться в этом, например, в netstat.
Странно. У меня на Linux локальные порты разные и не повторяются. Больше 10000 соединений я открывать не пробовал, но сделал вывод, что они не должны повторяться (т.е. при превышении 65535 будет ошибка соединения). Пробовал только с TCP соединениями. Но возможно я что-то не настроил. На следующих выходных набросаю программу проверки и попробую открыть больше 70000 соединений с трех-пяти виртуальных машин. ADD: Кажется надо включать SO_REUSERADDR. Тогда адреса используют один и тот же номер порта.
telnet как клиент --- Сообщение объединено, Nov 8, 2023 --- Кому интересно присоединяйтесь к разработке на XRDP dchub.one
А как это должно работать? Телнет - это же протокол для доступа к терминалу. Чат по телнету - это вообще как? К какому терминалу он будет соединяться?
ну хз как тебе объяснить, тут лыжи скорей всего, обе две --- Сообщение объединено, Nov 8, 2023 --- Протакол будет ограничен функциями сервера, я думаю в Си коде этот момент есть