2

接続を受け入れ、ユーザー指定のプログラムを実行して反対側と通信する、ほぼプロトタイプの 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$

read/write/close の代わりに send/recv/shutdown を使用する場合のように、execve されたプログラムはソケットをよりソケットのように扱うべきだと信じる準備ができていますが、これまでに見たドキュメントはclose() は設計どおりに機能し、シャットダウンは接続を半分閉じる場合にのみ必要であることを示唆しています。Unix Sockets FAQ では、未送信のデータは SO_LINGER オプションを設定せずに閉じるときにフラッシュする必要があると述べており、Linux の man ページ socket(7) では、「ソケットが exit(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);
    }
  }
}
4

0 に答える 0