4

私は最近 APUE.2e (UNIX® 環境での高度なプログラミング、第 2 版) を学んでおり、第 16 章のネットワーク IPC: ソケットにたどり着きました。プログラムruptimeを (クライアント エンド用) およびruptimed(サーバー エンド用) に実行すると、奇妙なことが起こりました。クライアント プログラムは、サーバーと通信してシステムのuptimeコマンドからの出力を取得するクライアント コマンドを示しています。サーバー プログラムruptimed(「d」に注意) はコマンドを受け取り、コマンドを実行してクライアントuptimeに出力を返しuptimeます。2 つのプログラムは正常にコンパイルさruptime 4000/tcpれ、ファイルに を追加します/etc/service。これは、サービスruptimeが port にバインドされることを意味します4000/tcp。同じマシン (Ubuntu 11.04) とruptimed最初の (もちろん)上で 2 つのプログラムを実行しました。

$ ./ruptimed
$ ./ruptime 127.0.0.1
 21:35:48 up 13:06,  3 users,  load average: 0.56, 0.85, 0.94 

出力は私が期待したものです。しかし、私が走ったとき:

$ ./ruptimed
$ ./ruptime 192.168.1.221
  # the terminal blocks here

IP アドレス 192.168.1.221 は、イントラネット内のマシンの実際の IP です。ここで何が問題なのですか?インターネットで検索したところ、 にシェルスクリプトが必要なようです/etc/init.d/ruptime次に、ディレクトリに名前が付けられたファイルを追加します/etc/init.d/。ここにあります:

#! /bin/sh

### BEGIN INIT INFO
# Provides:     ruptimed
# Required-Start:   $remote_fs $syslog
# Required-Stop:    $remote_fs $syslog
# Default-Start:    2 3 4 5
# Default-Stop:     
# Short-Description:    ruptime
### END INIT INFO
start()
{
    echo "start ruptime"
    /home/tlh1987/apue-practice/tlh-practice/ruptimed
    exit 0;
}
stop()
{
    killall ruptimed
    echo "stop ruptime"
}

case "$1" in
    start)
    start
    ;;
    stop)
    stop
    ;;
    restart)
    stop
    start
    ;;
    *)
    echo "usage: $0 start|stop|restart"
    exit 0;
esac

しかし、それはうまくいきませんでした。その理由はわかりません。また、次のように ufw を有効にして ruptime を許可しました。

sudo ufw allow ruptime

それもうまくいきませんでした。ruptimeとのソース コードはruptimed次のとおりです。

connect_retry()

// the  functions used in the two program
// the  connect_retry() function 
#include "apue.h"
#include <sys/socket.h>

#define MAXSLEEP 128

int
connect_retry(int sockfd, const struct sockaddr *addr, socklen_t alen)
{
  int nsec;

  for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) {
    if (connect(sockfd, addr, alen) == 0) {
      return (0);
    }
    if (nsec <= MAXSLEEP/2)
      sleep(nsec);
  }
  return (-1);
}

init_server()

// the initserver function 
#include "apue.h"
#include <errno.h>
#include <sys/socket.h>

int
initserver(int type, const struct sockaddr *addr, socklen_t alen, 
       int qlen)
{
  int fd;
  int err = 0;
  if ((fd = socket(addr->sa_family, type, 0)) < 0)
    return (-1);
  if (bind(fd, addr, alen) < 0) {
    err = errno;
    goto errout;
  }
  if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
    if (listen(fd, qlen) < 0) {
      err = errno;
      goto errout;
    }
  }
  return(fd);

 errout:
  close(fd);
  errno = err;
  return (-1);
}

クライアントエンド

// the client end i.e. ruptime.c
#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>

#define MAXADDRLEN 256

#define BUFLEN 128
extern int connect_retry(int, const struct sockaddr *, socklen_t);

void
print_uptime(int sockfd)
{
  int n;
  char buf[BUFLEN];

  while ((n = recv(sockfd, buf, BUFLEN, 0)) > 0)
    write(STDOUT_FILENO, buf, n);
  if (n < 0)
    err_sys("recv error");
}

int
main(int argc, char *argv[])
{
  struct addrinfo   *ailist, *aip;
  struct addrinfo    hint;
  int            sockfd, err;

  if (argc !=2 )
    err_quit("usage: ruptime hostname");
  hint.ai_flags = 0;
  hint.ai_family = 0;
  hint.ai_socktype = SOCK_STREAM;
  hint.ai_protocol = 0;
  hint.ai_addrlen = 0;
  hint.ai_canonname = NULL;
  hint.ai_addr = NULL;
  hint.ai_next = NULL;
  if ((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)
    err_quit("getaddrinfo error: %s", gai_strerror(err));
  for (aip = ailist; aip != NULL; aip = aip->ai_next) {
    if ((sockfd = socket(aip->ai_family, SOCK_STREAM, 0)) < 0)
      err = errno;
    if (connect_retry(sockfd, aip->ai_addr, aip->ai_addrlen) < 0) {
      err = errno;
    } else {
      print_uptime(sockfd);
      exit(0);
    }
  }
  fprintf(stderr, "can't connect to %s: %s\n", argv[1], 
      strerror(err));
  exit(1);
}

サーバーエンド

//the server end i.e. ruptimed is as follows:
#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <syslog.h>
#include <sys/socket.h>

#define BUFLEN 128
#define QLEN 10

#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif

extern int initserver(int, struct sockaddr *, socklen_t, int);

void
serve(int sockfd)
{
  int   clfd;
  FILE *fp;
  char buf[BUFLEN];

  for ( ; ; ) {
    clfd = accept(sockfd, NULL, NULL);
    if (clfd < 0) {
      syslog(LOG_ERR, "ruptimed: accept error: %s", 
         strerror(errno));
      exit(1);
    }
    if ((fp = popen("/usr/bin/uptime", "r")) == NULL) {
      sprintf(buf, "error: %s\n", strerror(errno));
      send(clfd, buf, strlen(buf), 0);
    } else {
      while (fgets(buf, BUFLEN, fp) != NULL)
    send(clfd, buf, strlen(buf), 0);
      pclose(fp);
    }
    close(clfd);
  }
}

int 
main(int argc, char *argv[])
{
  struct addrinfo   *ailist, *aip;
  struct addrinfo    hint;
  int            sockfd, err, n;
  char          *host;

  if (argc != 1)
    err_quit("usage: ruptimed");
#ifdef _SC_HOST_NAME_MAX
  n = sysconf(_SC_HOST_NAME_MAX);
  if (n < 0)
#endif 
    n = HOST_NAME_MAX;
  host = malloc(n);
  if (host == NULL)
    err_sys("malloc error");
  if (gethostname(host, n) < 0)
    err_sys("gethostname error");
  daemonize("ruptimed");
  hint.ai_flags = AI_CANONNAME;
  hint.ai_family = 0;
  hint.ai_socktype = SOCK_STREAM;
  hint.ai_protocol = 0;
  hint.ai_addrlen = 0;
  hint.ai_canonname = NULL;
  hint.ai_addr = NULL;
  hint.ai_next = NULL;
  if ((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0) {
    syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", 
       gai_strerror(err));
    exit(1);
  }
  for (aip = ailist; aip != NULL; aip = aip->ai_next) {
    if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr, 
                 aip->ai_addrlen, QLEN)) >= 0)
      serve(sockfd);
    exit(0);
  }
  exit(1);
}

助けてくれる人はいますか?

コマンド netstat -nap のヘッダー行:

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -               
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      -               
tcp        0      0 127.0.0.1:4000          0.0.0.0:*               LISTEN      2252/ruptimed   
tcp        0  13033 192.168.1.221:47380     91.189.89.114:443       LAST_ACK    -               
tcp       74      0 192.168.1.221:43914     91.189.89.76:443        ESTABLISHED 1846/python     
tcp        0      0 127.0.0.1:4000          127.0.0.1:56344         TIME_WAIT   -               
tcp        0      1 192.168.1.221:35442     192.168.1.89:24800      SYN_SENT    1478/synergyc   
tcp        0      0 192.168.1.221:34957     74.125.71.125:5222      ESTABLISHED 1618/chrome     
tcp        0      0 192.168.1.221:57795     203.208.46.163:443      ESTABLISHED 1618/chrome     
tcp6       0      0 :::22                   :::*                    LISTEN      -  

3 番目のレコードは、私のサービスの稼働時間です。それは何か間違っていますか?私はその意味についてあまり知りません。

4

2 に答える 2

7

私は C の専門家ではありませんが、1 つのことを知っています。デーモンはおそらく 1 つのアドレス/インターフェイスにのみバインドされており、そこからの接続のみを受け入れています。

netstat -napデーモンがバインドしているアドレスを確認するために使用します。

リッスンしている場合は0.0.0.0、localhost を含むすべてのインターフェイスからの接続を受け入れています。

リッスンしている場合は127.0.0.1、localhost からのみ受け入れます。

にしかバインドされて127.0.0.1いないので、他のアドレスには接続できません。

于 2012-04-09T14:22:18.263 に答える
1

これはほぼ確実にファイアウォールの問題であり、コーディングの問題ではありません。いくつかの ufw ドキュメントを見て、ufw 行でポートまたは IP アドレスを指定することをお勧めします。

于 2012-04-09T14:23:24.340 に答える