From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Date: Mon, 19 May 2003 15:38:00 +0400 From: Andrey Brindeew To: ALT Linux community Message-ID: <20030519113800.GA18016@abr.tool.ru> Mail-Followup-To: ALT Linux community Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="8P1HSweYDcXXzwPJ" Content-Disposition: inline Subject: [Comm] Q: Programming sockets in C language troubles Sender: community-admin@altlinux.ru Errors-To: community-admin@altlinux.ru X-BeenThere: community@altlinux.ru X-Mailman-Version: 2.0.9 Precedence: bulk Reply-To: community@altlinux.ru List-Unsubscribe: , List-Id: List-Post: List-Help: List-Subscribe: , List-Archive: Archived-At: List-Archive: List-Post: --8P1HSweYDcXXzwPJ Content-Type: multipart/mixed; boundary="GvXjxJ+pjyke8COw" Content-Disposition: inline Content-Transfer-Encoding: 8bit --GvXjxJ+pjyke8COw Content-Type: text/plain; charset=koi8-r Content-Disposition: inline Content-Transfer-Encoding: 8bit Hi! На работе встала задача перегонять данные с одной машины (расчетная, сервер) на другую (отображение) по сети. В качестве языка используется Си, ОС Linux, поэтому было решено использовать сокеты для передачи, дабы ничего не изобретать ("всё уже украдено до нас" (C) :-) ) Берем тривиальный пример из документации по glibc (pinfo select, самая последняя ссылка на странице: Server Example). Чуть-чуть дорабатываем (избавляемся от функции make_socket путем включения ее в программу) и пытаемся тестить: $ gcc -o srv{,.c} $ ./srv На другой консоли: $ telnet 127.0.0.1 1200 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. protocol_command 12345 Переключаемся на серверную консоль: _тишина полная_. Нажимаем Enter три (или больше) раз - видим следующее: $ ./srv got message from 0 client: ` ╛@пВЪ©PВЪ©└' got message from 1 client: ` ╛@пВЪ©PВЪ©└' got message from 2 client: ` ╛@пВЪ©PВЪ©└' connect from host 127.0.0.1, port 33683. got message from 4 client: `protocol_com─ЖЪ©L╛@L╛@ХВЪ©┼' read: Bad file descriptor Теперь вопросы: 1. Почему у нас на серверной консоли фигурируют 0, 1 и 2 сокеты (я так понимаю, что это stdin, stdout и stderr сервера собственной персоной)? Я их в FD_SET не заказывал на прослушивание с помощью select. :-( 2. Что за мусор идет после подстроки "protocol_com"? Я так понимаю, что буфер чтения у сокета заполнился (ибо 12 символов всего), но откуда мусор? 3. Почему сообщение о подсоединении клиента не появилось сразу же после того, как я подцепился к серверу с помощью telnet? 4. Я наверное еще много чего не понимаю, какая хорошая литература есть в сети и код какой _хорошо написанной_ программы можно посмотреть для примера? В исходниках sshd и popa3d запутался... :-( Для желающих помочь начинающему Си-программисту советом код "сервера" прицеплен к письму. P.S. Первоначальная идея состояла в том, чтобы написать расчетный сервер, который работает по следующему протоколу: получает номер алгоритма и (опционально) параметры для расчета по этому алгоритму, а потом начинает тупо писать в открытый сокет рассчитываемые данные, пока этот сокет удаленная сторона (визуализирующий клиент) не закроет. Клиент реально будет один, но закладываться на одноклиентную архитектуру при написании не хотелось бы. -- WBR, Andrey Brindeew. "No one person can understand Perl culture completely" (C) Larry Wall. --GvXjxJ+pjyke8COw Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="srv.c" #include #include #include #include #include #include #include #include #define PORT 1200 #define MAXMSGLENGTH 12 int main (void) { int sock; /* server socket, which accepts new connections */ fd_set active_fd_set, read_fd_set; /* sets of serving socket descriptors */ int i; struct sockaddr_in clientname, server; size_t size; /* Create the socket and set it up to accept connections */ sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(EXIT_FAILURE); } /* Give the socket a name */ server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { perror("bind"); exit(EXIT_FAILURE); } if (listen(sock, 10) < 0) { perror("listen"); exit(EXIT_FAILURE); } /* Initialize the set of active sockets */ FD_ZERO (&active_fd_set); FD_SET (sock, &active_fd_set); /* going into server main loop */ while (1) { /* Block until unput arrives on one or more active sockets */ read_fd_set = active_fd_set; if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) { perror ("select"); exit (EXIT_FAILURE); } /* Service all sockets with input pending */ for (i = 0; i < FD_SETSIZE; ++i) { if (i == sock) { /* Connection on server socket - new connection request */ int new; size = sizeof (clientname); new = accept(sock, (struct sockaddr *) &clientname, &size); if (new < 0) { perror ("accept"); exit (EXIT_FAILURE); } fprintf (stderr, "connect from host %s, port %hd.\n", inet_ntoa (clientname.sin_addr), ntohs(clientname.sin_port)); FD_SET (new, &active_fd_set); } else { if (read_from_client (i) < 0) { close (i); FD_CLR (i, &active_fd_set); } } } } } int read_from_client (int fd) { char buffer[MAXMSGLENGTH]; int nbytes; nbytes = read (fd, buffer, MAXMSGLENGTH); if (nbytes < 0) { perror("read"); exit(EXIT_FAILURE); } else if (nbytes == 0) { return -1; } else { fprintf (stderr, "got message from %d client: `%s'\n", fd, buffer); return 0; } } --GvXjxJ+pjyke8COw-- --8P1HSweYDcXXzwPJ Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) Comment: Get my public key at http://abr.pp.ru/gpg.html iD8DBQE+yMIY3gaCZ4hbZncRAuNPAJ9m5jLLjyMQusyw06OW/ZUxbRXN+gCgpzvX 40ncn00NJ1ONY96qCf/Z97A= =vj1u -----END PGP SIGNATURE----- --8P1HSweYDcXXzwPJ--