* [Comm] Q: Programming sockets in C language troubles
@ 2003-05-19 11:38 Andrey Brindeew
2003-05-19 11:48 ` Sergey Bolshakov
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Andrey Brindeew @ 2003-05-19 11:38 UTC (permalink / raw)
To: ALT Linux community
[-- Attachment #1.1: Type: text/plain, Size: 2401 bytes --]
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.
[-- Attachment #1.2: srv.c --]
[-- Type: text/plain, Size: 2391 bytes --]
#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;
}
}
[-- Attachment #2: Type: application/pgp-signature, Size: 245 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Comm] Q: Programming sockets in C language troubles
2003-05-19 11:38 [Comm] Q: Programming sockets in C language troubles Andrey Brindeew
@ 2003-05-19 11:48 ` Sergey Bolshakov
2003-05-19 11:55 ` Sergey Bolshakov
2003-05-19 12:05 ` Sergey Vlasov
2003-05-19 12:14 ` [Comm] " Dmitry V. Levin
2 siblings, 1 reply; 6+ messages in thread
From: Sergey Bolshakov @ 2003-05-19 11:48 UTC (permalink / raw)
To: ALT Linux community
>>>>> "Andrey" == Andrey Brindeew <abr@altlinux.ru> writes:
> Hi!
> На работе встала задача перегонять данные с одной машины (расчетная,
> сервер) на другую (отображение) по сети. В качестве языка используется
> Си, ОС Linux, поэтому было решено использовать сокеты для передачи, дабы
> ничего не изобретать ("всё уже украдено до нас" (C) :-) )
> Берем тривиальный пример из документации по glibc (pinfo select, самая
> последняя ссылка на странице: Server Example). Чуть-чуть дорабатываем
> (избавляемся от функции make_socket путем включения ее в программу) и
> пытаемся тестить:
[skipped]
Первое, что приходит в голову - не надо тестить телнетом, он для
более другого предназначен. Возьмите, например, netcat.
--
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Comm] Q: Programming sockets in C language troubles
2003-05-19 11:48 ` Sergey Bolshakov
@ 2003-05-19 11:55 ` Sergey Bolshakov
0 siblings, 0 replies; 6+ messages in thread
From: Sergey Bolshakov @ 2003-05-19 11:55 UTC (permalink / raw)
To: community
>>>>> "Sergey" == Sergey Bolshakov <s.bolshakov@sam-solutions.net> writes:
>>>>> "Andrey" == Andrey Brindeew <abr@altlinux.ru> writes:
>> Hi!
>> На работе встала задача перегонять данные с одной машины (расчетная,
>> сервер) на другую (отображение) по сети. В качестве языка используется
>> Си, ОС Linux, поэтому было решено использовать сокеты для передачи, дабы
>> ничего не изобретать ("всё уже украдено до нас" (C) :-) )
>> Берем тривиальный пример из документации по glibc (pinfo select, самая
>> последняя ссылка на странице: Server Example). Чуть-чуть дорабатываем
>> (избавляемся от функции make_socket путем включения ее в программу) и
>> пытаемся тестить:
> [skipped]
> Первое, что приходит в голову - не надо тестить телнетом, он для
> более другого предназначен. Возьмите, например, netcat.
Второе, что пришло в голову :) - им и ограничиться, пуская сервер
из-под xinetd.
--
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Comm] Q: Programming sockets in C language troubles
2003-05-19 11:38 [Comm] Q: Programming sockets in C language troubles Andrey Brindeew
2003-05-19 11:48 ` Sergey Bolshakov
@ 2003-05-19 12:05 ` Sergey Vlasov
2003-05-23 11:28 ` [Comm] " Andrey Brindeew
2003-05-19 12:14 ` [Comm] " Dmitry V. Levin
2 siblings, 1 reply; 6+ messages in thread
From: Sergey Vlasov @ 2003-05-19 12:05 UTC (permalink / raw)
To: ALT Linux community
On Mon, May 19, 2003 at 15:38:00 +0400, Andrey Brindeew wrote:
[skip]
> 1. Почему у нас на серверной консоли фигурируют 0, 1 и 2 сокеты (я
> так понимаю, что это stdin, stdout и stderr сервера собственной
> персоной)? Я их в FD_SET не заказывал на прослушивание с помощью
> select. :-(
Там в цикле ещё должна была быть проверка FD_ISSET(i, &read_fd_set).
И обычно вместо FD_SETSIZE ставят max(fd) + 1, чтобы не проверялись
лишние биты.
> 2. Что за мусор идет после подстроки "protocol_com"? Я так понимаю, что
> буфер чтения у сокета заполнился (ибо 12 символов всего), но откуда
> мусор?
А кто будет \0 в конце для printf добавлять?
> 3. Почему сообщение о подсоединении клиента не появилось сразу же после
> того, как я подцепился к серверу с помощью telnet?
Так из-за отсутствия проверки FD_ISSET она и ждала ввода из stdin.
[skip]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Comm] Q: Programming sockets in C language troubles
2003-05-19 11:38 [Comm] Q: Programming sockets in C language troubles Andrey Brindeew
2003-05-19 11:48 ` Sergey Bolshakov
2003-05-19 12:05 ` Sergey Vlasov
@ 2003-05-19 12:14 ` Dmitry V. Levin
2 siblings, 0 replies; 6+ messages in thread
From: Dmitry V. Levin @ 2003-05-19 12:14 UTC (permalink / raw)
To: ALT Linux general discussion list
[-- Attachment #1: Type: text/plain, Size: 2288 bytes --]
On Mon, May 19, 2003 at 03:38:00PM +0400, Andrey Brindeew wrote:
> На работе встала задача перегонять данные с одной машины (расчетная,
> сервер) на другую (отображение) по сети. В качестве языка используется
> Си, ОС 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
$ apropos telnet netcat
telnet (1) - user interface to the TELNET protocol
netcat (1) - arbitrary TCP and UDP connections and listens
> Переключаемся на серверную консоль: _тишина полная_.
> Нажимаем Enter три (или больше) раз - видим следующее:
>
> $ ./srv
>
> got message from 0 client: `
> ╛@пВЪ©PВЪ©└'
Это telnet protocol, RFC 854.
[...]
> Теперь вопросы:
> 1. Почему у нас на серверной консоли фигурируют 0, 1 и 2 сокеты (я
> так понимаю, что это stdin, stdout и stderr сервера собственной
> персоной)? Я их в FD_SET не заказывал на прослушивание с помощью
> select. :-(
А кто будет FD_ISSET делать?
> 2. Что за мусор идет после подстроки "protocol_com"? Я так понимаю, что
> буфер чтения у сокета заполнился (ибо 12 символов всего), но откуда
> мусор?
Это telnet protocol, RFC 854.
> 3. Почему сообщение о подсоединении клиента не появилось сразу же после
> того, как я подцепился к серверу с помощью telnet?
Это telnet protocol, RFC 854.
> 4. Я наверное еще много чего не понимаю, какая хорошая литература есть
> в сети и код какой _хорошо написанной_ программы можно посмотреть
> для примера? В исходниках sshd и popa3d запутался... :-(
Stevens W.R. UNIX Network Programming, Volume 1, Second Edition,
Networking APIs: Sockets and XTI // Prentice Hall, Upper Saddle River,
N.J., 1998
Есть (в Москве наверняка) перевод на русский язык, но имейте в виду, что,
в отличие от перевода второго тома, перевод этого тома содержит тьму
ошибок.
--
ldv
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Comm] Re: Q: Programming sockets in C language troubles
2003-05-19 12:05 ` Sergey Vlasov
@ 2003-05-23 11:28 ` Andrey Brindeew
0 siblings, 0 replies; 6+ messages in thread
From: Andrey Brindeew @ 2003-05-23 11:28 UTC (permalink / raw)
To: ALT Linux community
[-- Attachment #1.1: Type: text/plain, Size: 1100 bytes --]
On Mon, May 19, 2003 at 04:05:51PM +0400, Sergey Vlasov wrote:
> Там в цикле ещё должна была быть проверка FD_ISSET(i, &read_fd_set).
Oops, спасибо, я её пропустил при перенаборе (странно, но пара строк при
печати из pinfo пропадает - нет ни на первом, ни на втором листе!)
> И обычно вместо FD_SETSIZE ставят max(fd) + 1, чтобы не проверялись
> лишние биты.
Я не совсем понимаю, как работают указанные макросы, поэтому последовал
примеру.
> А кто будет \0 в конце для printf добавлять?
> Так из-за отсутствия проверки FD_ISSET она и ждала ввода из stdin.
Заработало, большое спасибо.
Всё работает замечательно, за исключением одного "но" - прототип клиента
вычисляет, что пропускная способность сети - 2.94Mb/sec! Никак не могу
понять, в чем я лопухнулся. gkrellm показывает 1.2-1.3M.
Время высчитываю как разницу между вызовами ntp_gettime, беру количество
принятых структур, умножаю на sizeof(принимаемая структура), делю на
время. Скорость упорно показывается ~2.94Mb/сек. :-(
Код в аттаче.
--
WBR, Andrey Brindeew.
"No one person can understand Perl culture completely"
(C) Larry Wall.
[-- Attachment #1.2: transfer-mini-server.tgz --]
[-- Type: application/x-gzip, Size: 3202 bytes --]
[-- Attachment #2: Type: application/pgp-signature, Size: 245 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2003-05-23 11:28 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-05-19 11:38 [Comm] Q: Programming sockets in C language troubles Andrey Brindeew
2003-05-19 11:48 ` Sergey Bolshakov
2003-05-19 11:55 ` Sergey Bolshakov
2003-05-19 12:05 ` Sergey Vlasov
2003-05-23 11:28 ` [Comm] " Andrey Brindeew
2003-05-19 12:14 ` [Comm] " Dmitry V. Levin
ALT Linux Community general discussions
This inbox may be cloned and mirrored by anyone:
git clone --mirror http://lore.altlinux.org/community/0 community/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 community community/ http://lore.altlinux.org/community \
mandrake-russian@linuxteam.iplabs.ru community@lists.altlinux.org community@lists.altlinux.ru community@lists.altlinux.com
public-inbox-index community
Example config snippet for mirrors.
Newsgroup available over NNTP:
nntp://lore.altlinux.org/org.altlinux.lists.community
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git