webbench中套接字 进程 通信 信号相关编程

https://docs.scrapy.org/en/latest/intro/tutorial.html

https://github.com/qianlizhixing12/webbench

c++重构webbench,学习socket编程,fork进程,进程间通信

socket网络编程

static int Socket(const string &host, int port) {
  // sockaddr_in
  struct sockaddr_in ad;
  memset(&ad, 0, sizeof(ad));
  ad.sin_family = AF_INET;
  if (unsigned long inaddr = inet_addr(host.c_str()) != INADDR_NONE)
    memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
  else {
    struct hostent *hp = gethostbyname(host.c_str());
    if (hp == NULL) {
      return -1;
    }
    memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
  }
  ad.sin_port = htons(port);
  // socket
  int sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0) {
    return sock;
  }
  if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0) {
    return -1;
  }
  return sock;
}
  • inet_addr将一个点分十进制的IP字符串转换成一个长整数型数,失败返回INADDR_NONE
  • gethostbyname从dns域名系统获取ip地址信息
  • htons把机器上的整数转换成网络字节序(big-endian,即整数的高位字节存放在内存的低地址处)
  • socket建立套接字
  • connect建立tcp连接

fork复制进程

  /* fork childs */
  pid_t pid = 0;
  int i = 0;
  for (i = 0; i < clients; i++) {
    pid = fork();
    // 子进程不循环
    if (pid <= (pid_t)0) {
      /* child process or error*/
      sleep(1); /* make childs faster */
      break;
    }
  }
  if (pid < (pid_t)0) {
    cout << "problems forking worker no." << i << endl;
    perror("fork failed.");
    exit(3);
  } else if (pid == (pid_t)0) {
    bench_child(mypipe[1], host, port, benchtime, data, http_version,
                http_force);
  } else {
    bench_father(mypipe[0], clients, benchtime);
  }
  • fork复制进程(包括运行堆栈信息),复制失败返回负值,成功时父进程中返回子进程pid,子进程中返回0

pipe(管道)进程通信

  int mypipe[2];
  if (pipe(mypipe)) {
    perror("pipe failed.");
    exit(3);
  }

static void bench_father(const int pipeno, int clients, const int benchtime) {
  FILE *f = fdopen(pipeno, "r");
  if (f == NULL) {
    perror("open pipe for reading failed.");
    exit(3);
  }
  setvbuf(f, NULL, _IONBF, 0);
  int speed = 0;
  int failed = 0;
  int bytes = 0;
  int i, j, k;

  while (1) {
    if (fscanf(f, "%d %d %d", &i, &j, &k) < 2) {
      cout << "Some of our childrens died." << endl;
      break;
    }
    speed += i;
    failed += j;
    bytes += k;
    /* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */
    if (--clients == 0)
      break;
  }
  fclose(f);
}

/* write results to pipe */
  FILE *f = fdopen(pipeno, "w");
  if (f == NULL) {
    perror("open pipe for writing failed.");
    exit(3);
  }
  fprintf(f, "%d %d %d\n", speed, failed, bytes);
  fclose(f);
  • pipe建立管道,成功返回0,失败返回非0值,管道是半双工的,数据单方向流动;mypipe管道两个文件描述符, 管道的两端是固定的。文件描述符mypipe[0]表示读端,文件描述符mypipe[1]表示写端,有了这两个描述符,可用一般文件的I/O函数(如close、read、write)用于管道通信

sigaction信号处理

volatile int timerexpired = 0;

static void alarm_handler(int signal) { timerexpired = 1; }

static void bench_child(const int pipeno, const string &host, const int port,
                        const int benchtime, const string &data,
                        const string &http_version, bool http_force) {
  /* setup alarm signal handler */
  struct sigaction sa;
  sa.sa_handler = alarm_handler;
  sa.sa_flags = 0;
  if (sigaction(SIGALRM, &sa, NULL)) {
    exit(3);
  }
  alarm(benchtime);
  int speed = 0;
  int failed = 0;
  int bytes = 0;
  // int len = ;
nexttry:
  while (1) {
    if (timerexpired) {
      if (failed > 0) {
        failed--;
      }
      break;
    }
    int s = Socket(host, port);
    if (s < 0) {
      failed++;
      continue;
    }
    if (data.size() != write(s, data.c_str(), data.size())) {
      failed++;
      close(s);
      continue;
    }
    if (close(s)) {
      failed++;
      continue;
    }
    speed++;
  }
}
  • 这里是用信号实现定时器
  • sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)信号设置
    • signum要操作的信号
    • act信号处理方式,sa.sa_handler处理函数
    • oldact原信号处理方式
    • 返回值0成功,-1有错误
  • alarm(seconds)设置信号SIGALRM经过seconds秒数后传送给当前进程,seconds为0之前设置闹钟会取消,并将剩下的时间返回,一个进程只能有一个闹钟时间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值