Пренасочване на STDOUT и STDERR към сокет в C?

Опитвам се да пренасоча STDOUT И STDERR към сокет.

Направих:

if(fork() == 0)
{
   dup2(newsock, STDOUT_FILENO);
   dup2(newsock, STDERR_FILENO);
   execvp();
}

По някакъв начин показа само първата малка част от резултата.

например, показваше се на "mkdir", когато се опитвам да изпълня ls или mkdir.

Какъв е проблема?

Опитах следното, работи, но мога да пренасоча само един от STDOUT или STDERR

close(1);
dup(newsock);

Благодаря много.


person JJ Liu    schedule 11.11.2011    source източник
comment
@Дмитри, бихте ли ми помогнали с това? Благодаря!   -  person JJ Liu    schedule 12.11.2011


Отговори (4)


Използването на dup2() изглежда добре, така че проблемът вероятно е другаде. Простата програма, която събрах, за да тествам, няма проблемите, които изпитвате, така че просто ще прегледам ядрото й (около областта fork()/execvp()), като някои проверки за грешки ще бъдат пропуснати за краткост:

int    lsock, /* listening socket */
       csock; /* active connection's socket */
pid_t  cpid;  /* child process ID from fork() */
char   *cmd = "somecommand";
char   *cmd_args[] = { "somecommand",
                       "firstarg",
                       "secondarg",
                       "howevermanyargs",
                       NULL }; /* note: last item is NULL */
/*  ... 
    call socket(), bind(), listen(), etc.
    ... */

for (;;) {  /* loop, accepting connections */
  if ( (csock = accept( lsock, NULL, NULL )) == -1) exit(1);
  cpid = fork();
  if (cpid < 0) exit(1);  /* exit if fork() fails */
  if ( cpid ) {
    /* In the parent process: */
    close( csock ); /* csock is not needed in the parent after the fork */
    waitpid( cpid, NULL, 0 ); /* wait for and reap child process */
  } else {
    /* In the child process: */
    dup2( csock, STDOUT_FILENO );  /* duplicate socket on stdout */
    dup2( csock, STDERR_FILENO );  /* duplicate socket on stderr too */
    close( csock );  /* can close the original after it's duplicated */
    execvp( cmd, cmd_args );   /* execvp() the command */
  }
}

Горното е ядрото на много основен сървър (само един клиент наведнъж), който, когато получи връзка, разклонява нов процес, за да изпълни команда и изпраща своя stderr и stdout на клиента през сокета. Надяваме се, че можете да разрешите проблема си, като го проучите - но не просто копирайте кода, без да разбирате какво прави.

Опитайте да тествате, като първо се свържете с telnet клиент... ако работи с telnet, но не и с вашата клиентска програма, тогава потърсете проблеми във вашата клиентска програма.

person Dmitri    schedule 12.11.2011

Използването на dup2 е правилно. Вашите извиквания за запис не записват целия буфер, който им предоставяте, тъй като данните все още не са получени от отдалечения партньор и буферът на ядрото, определен за това, вероятно е пълен. Типичният размер на буфера е 64KB. Трябва да се уверите, че приемникът получава данните и да увиете вашите записи в цикъл. Като алтернатива използвайте MSG_SENDALL и системното повикване send.

person Matt Joiner    schedule 12.11.2011
comment
Благодаря. оказва се, че ls работи добре и може да изведе цялата директория. така че STDOUT работи добре. но когато трябва да върне mkdir: sampledirectory already exist, той връща само mkdir - person JJ Liu; 12.11.2011
comment
Здравейте, току-що видях тази публикация и имам този проблем. Когато пренасочвам stdout към новия сокет и използвам exec, понякога той ще запази датата в буфера и ще ги отпечата цикъл след това. Какво точно трябва да направя? Къде да направя този цикъл от WRITEs?? - person Panagiss; 22.01.2020

Прочетете отново страницата man dup2 (откъси):

 SYNOPSIS
   int dup2(int oldfd, int newfd);

 DESCRIPTION
   dup2() makes newfd be the copy of oldfd, closing newfd 

Така че трябва да бъде dup2 (STDOUT_FILENO, newsock);

person Basile Starynkevitch    schedule 11.11.2011
comment
не, това е точно назад. операторът иска newsock да стане STDOUT_FILENO. - person zwol; 12.11.2011
comment
Но той написа: Опитвам се да пренасоча STDOUT И STDERR към сокет. Не съм роден английски (тъй като съм французин), но предлогът to не показва ли дестинацията? - person Basile Starynkevitch; 12.11.2011
comment
@BasileStarynkevitch Сокетът е местоназначението, но това е местоназначението на данните -- което означава, че всичко, което е записано в stdout или stderr, трябва да бъде изпратено до сокета. За да направи това, той трябва да направи stdout и stderr дубликати на сокета. - person Dmitri; 12.11.2011
comment
@BasileStarynkevitch Това е досадна грешка в man страницата на dup2. Редът на аргументите е обратен. - person Samy Dindane; 26.05.2013
comment
dup2 (STDOUT_FILENO, newsock); ще затвори гнездото според цитирания от вас откъс. OP иска да запази сокета отворен и да пренасочи изхода към него. За да направи това, той трябва да затвори стария stdout и да го направи копие на сокета с dup2 (newsock, STDOUT_FILENO); - person interjay; 20.12.2015

Мисля, че проблемът е, че stderr и stdout са едни и същи на някои системи

person Brett Silverman    schedule 01.12.2020