[Comm] Q: Programming sockets in C language troubles
Andrey Brindeew
=?iso-8859-1?q?abr_=CE=C1_altlinux=2Eru?=
Пн Май 19 15:38:00 MSD 2003
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.
----------- следующая часть -----------
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#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;
}
}
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя : =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Тип : application/pgp-signature
Размер : 245 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url : <http://lists.altlinux.org/pipermail/community/attachments/20030519/38cb3288/attachment-0004.bin>
Подробная информация о списке рассылки community