данные исчезают в (TCP) сокете - PullRequest
2 голосов
/ 12 июня 2011

У меня есть этот в основном прототипный сервер сокетов TCP, который принимает соединение, а затем запускает указанную пользователем программу для связи с другой стороной.Загадочная вещь заключается в том, что write () вызывается и возвращает, но клиент не получает никаких выходных данных.

Вывод strace (с запущенной программой "cat") выглядит следующим образом:

[pid  8142] read(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 32768) = 292
[pid  8142] write(1, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 292) = 292
[pid  8142] read(0, "", 32768)          = 0
[pid  8142] close(0)                    = 0
[pid  8142] close(1)                    = 0
[pid  8142] close(2)                    = 0

в то время как на стороне клиента ничего не происходит:

shell$ seq 100 | nc localhost 4445
shell$

Я был бы готов поверить, что программа execve должна обрабатывать сокет как сокет, как при использовании send/ recv / shutdown вместо read / write / close - но документация, которую я до сих пор видел, похоже, предполагает, что close () должна работать как задумано, а завершение работы будет необходимо только для полузакрытия соединения. FAQ по сокетам Unix упоминает, что неотправленные данные должны сбрасываться при закрытии без установки каких-либо параметров SO_LINGER, а сокет man-страницы Linux (7) утверждает, что " Когда сокет закрыт как часть выхода (2), он всегда задерживается в фоновом режиме."Предоставление достаточного количества выходных данных приводит к тому, что первая часть отправляется клиенту.

Ради полноты, вот программа ...

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/net.h>
#include <netinet/in.h>

static int sock_fd_listen;
static struct sockaddr_in my_addr = {PF_INET, 0x5d11, 0x0100007f};
static struct 
static int one=1;
static int sockargs[]={0, 0, 0};

extern char **environ;

void step1()
{
  int retval;
  sock_fd_listen=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  retval=bind(sock_fd_listen, (struct sockaddr *)&my_addr,
          sizeof(struct sockaddr_in));
  if (retval==-1) {
    perror("bind");
    exit(1);
  }
  setsockopt(sock_fd_listen, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
  listen(sock_fd_listen, 5);
}


void main(int argc, char *argv[])
{
  static char buf[4096];
  int nconn=0;
  step1();
  while (1) {
    int conn_sock;
    pid_t pid;
    sockargs[0]=sock_fd_listen;
    conn_sock=accept(sock_fd_listen,NULL,NULL);
    pid=fork();
    if (pid==0) {
      dup2(conn_sock,0);
      dup2(conn_sock,1);
      close(conn_sock);
      execve(argv[1],argv+1,environ);
      fprintf(stderr, "execve failed: %s\n",strerror(errno));
      exit(-1);
    } else {
      close(conn_sock);
    }
  }
}
...