0

このコードは一日中台無しになりました。基本的に、管理している50のWebサーバーのリストがあり、それらが稼働しているかどうかを確認したい(isAlive()関数)、50のips / hostnameでwebservers.txtファイルを解析し、堅牢性のためにスレッドを使用しようとしています(10 、20または30は関係ありません)その後、コンパイルされたコードは何もせずに終了するように見えます...何かアイデア/ヘルプはありますか?

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#include <process.h>
#include <string.h>

#pragma comment(lib, "wsock32.lib")

unsigned int _stdcall isAlive(void *ptr)
{
  struct sockaddr_in blah;
  struct hostent *he;
  WSADATA wsaData;
  int i;
  WORD wVersionRequested;
  SOCKET sock;
  char* addr = (char*)ptr;

  char buff[1024];
  char *ex;
  ex="GET /alive.php HTTP/1.0\n\n";
  char *fmsg="ALIVE";

  wVersionRequested = MAKEWORD(1, 1);
  if (WSAStartup(wVersionRequested , &wsaData)){
    printf("Winsock Initialization failed.\n");
    return(1);
  }

  if ((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){
    printf("Can not create socket.\n");
    return(1);
  }
  sock = socket(AF_INET,SOCK_STREAM,0);
  blah.sin_family = AF_INET;
  blah.sin_port = htons(80);
  blah.sin_addr.s_addr = inet_addr(addr);

  if ((he=gethostbyname(addr))!=NULL){
    memcpy((char *)&blah.sin_addr.s_addr,he->h_addr,he->h_length);
  }
  else{
    if((blah.sin_addr.s_addr=inet_addr(addr))==-1){
      WSACleanup();
      return(1);
    }
  }

  if (connect(sock,(struct sockaddr*)&blah,sizeof(blah))==0){
    send(sock,ex,strlen(ex),0);
    recv(sock,buff,sizeof(buff),0);
    if(strstr(buff,fmsg)!=NULL){
      printf("ALIVE: %s", addr);
    }
  }

  closesocket(sock);
  WSACleanup();
  _endthreadex(0);
  return(1);
}

int main(int argc,char *argv[])
{
  if(argc!=2){
    printf("Usage: %s <webservers list>\n", argv[0]);
    return(1);
  }

  char *inname = argv[1];
  FILE *infile;
  char line_buffer[BUFSIZ];
  char line_number;

  infile = fopen(inname, "r");
  if (!infile) {
    printf("Couldn't open file %s for reading.\n", inname);
    return 0;
  }

  line_number = 0;
  HANDLE hThreadArray[200];
  while (fgets(line_buffer, sizeof(line_buffer), infile)) {
    ++line_number;
    unsigned threadID;
    hThreadArray[line_number] = (HANDLE)_beginthreadex(0, 0, isAlive, line_buffer, 0, &threadID);
  }
  WaitForMultipleObjects(sizeof(line_buffer), hThreadArray, TRUE, INFINITE);
  return 0;
}

あなたのアドバイスの後の新しいコード:

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#include <process.h>
#include <string.h>

#pragma comment(lib, "wsock32.lib")

unsigned int _stdcall isAlive(void *ptr)
{
  struct sockaddr_in blah;
  struct hostent *he;
  WSADATA wsaData;
  int i;
  WORD wVersionRequested;
  SOCKET sock;
  char* addr = (char*)ptr;

  char buff[1024];
  char *ex;
  ex="GET /alive.php HTTP/1.1\n\n";
  char *fmsg="ALIVE";

  wVersionRequested = MAKEWORD(1, 1);
  if (WSAStartup(wVersionRequested , &wsaData)){
    printf("Winsock Initialization failed.\n");
    return(1);
  }

  if ((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){
    printf("Can not create socket.\n");
    return(1);
  }
  sock = socket(AF_INET,SOCK_STREAM,0);
  blah.sin_family = AF_INET;
  blah.sin_port = htons(80);
  blah.sin_addr.s_addr = inet_addr(addr);

  if ((he=gethostbyname(addr))!=NULL){
    memcpy((char *)&blah.sin_addr.s_addr,he->h_addr,he->h_length);
  }
  else{
    if((blah.sin_addr.s_addr=inet_addr(addr))==-1){
      WSACleanup();
      return(1);
    }
  }

  if (connect(sock,(struct sockaddr*)&blah,sizeof(blah))==0){
    send(sock,ex,strlen(ex),0);
    recv(sock,buff,sizeof(buff),0);
    if(strstr(buff,fmsg)!=NULL){
      printf("ALIVE: %s\n", addr);
    }
  }

  closesocket(sock);
  WSACleanup();
  _endthreadex(0);
  return(1);
}

int main(int argc,char *argv[])
{
  if(argc!=2){
    printf("Usage: %s <webservers list>\n", argv[0]);
    return(1);
  }

  char *inname = argv[1];
  FILE *infile;
  char line_buffer[10000];
  char line_number;

  infile = fopen(inname, "r");
  if (!infile) {
    printf("Couldn't open file %s for reading.\n", inname);
    return 0;
  }

  line_number = 0;
  HANDLE hThreadArray[200];
  while (fgets(line_buffer, sizeof(line_buffer), infile)) {
    unsigned threadID;
    hThreadArray[line_number] = (HANDLE)_beginthreadex(0, 0, isAlive, line_buffer, 0, &threadID);
    ++line_number;
  }
  WaitForMultipleObjects(line_number, hThreadArray, TRUE, INFINITE);
  fclose(infile);
  return 0;
}

これでコードは実行されますが、テキストの最後の行を取得し、それを使用して複数のスレッドを作成します。

hosts.txt(11行)

myhost.com
mysecondhost.com
...
mylasthost.com

結果:C:\ Documents and Settings \ Xtmtrx \ Desktop \ Code> checkalive.exe hosts.txt

ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com

私がこれを行う場合:

#define MAX 10000

/* snip */

HANDLE hThreadArray[200];
char str[MAX];
char *x[MAX];
int i =0;

while(!feof(infile)) {
  while(fgets(str, sizeof str, infile)) {
    unsigned threadID;
    x[i] = strdup(str);
    printf("%s", *(x+i));
    hThreadArray[i] = (HANDLE)_beginthreadex(0, 0, isAlive, *(x+i), 0, &threadID);
    i++;
  }
}

正しいでしょうか?

最終編集:

これは私の完成したコードであり、機能しているようです。タイムアウトも追加しましたが、一部のホストでハングする可能性があるため、考慮されていないようです。

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#include <process.h>
#include <string.h>

#pragma comment(lib, "wsock32.lib")

#define MAX 10000

unsigned int _stdcall isAlive(void *ptr)
{
  struct sockaddr_in blah;
  struct hostent *he;
  WSADATA wsaData;
  int i;
  WORD wVersionRequested;
  SOCKET sock;
  char* addr = (char*)ptr;

  char buff[1024];
  char *request;
  request="GET /alive.php HTTP/1.0\n\n";
  char *fmsg="ALIVE";

  wVersionRequested = MAKEWORD(1, 1);
  if (WSAStartup(wVersionRequested , &wsaData)){
    printf("Winsock Initialization failed.\n");
    return(1);
  }

  if ((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){
    printf("Can not create socket.\n");
    return(1);
  }
  sock = socket(AF_INET,SOCK_STREAM,0);
  blah.sin_family = AF_INET;
  blah.sin_port = htons(80);
  blah.sin_addr.s_addr = inet_addr(addr);

  if ((he=gethostbyname(addr))!=NULL){
    memcpy((char *)&blah.sin_addr.s_addr,he->h_addr,he->h_length);
  }
  else{
    if((blah.sin_addr.s_addr=inet_addr(addr))==-1){
      WSACleanup();
      return(1);
    }
  }

  if (connect(sock,(struct sockaddr*)&blah,sizeof(blah))==0){
    send(sock,request,strlen(request),0);
    recv(sock,buff,sizeof(buff),0);
    if(strstr(buff,fmsg)!=NULL){
      printf("ALIVE: %s", addr);
    }
  }

  closesocket(sock);
  WSACleanup();
  _endthreadex(0);
  return(1);
}

int main(int argc,char *argv[])
{
  if(argc!=2){
    printf("Usage: %s <webservers list>\n", argv[0]);
    return(1);
  }

  char *inname = argv[1];
  FILE *infile;
  char line_buffer[BUFSIZ];
  char line_number;

  infile = fopen(inname, "r");
  if (!infile) {
    printf("Couldn't open file %s for reading.\n", inname);
    return 0;
  }

  HANDLE hThreadArray[200];
  char str[MAX];
  char *x[MAX];
  int i = 0;
  while(!feof(infile)) {
    while(fgets(str, sizeof str, infile)) {
      unsigned threadID;
      x[i] = strdup(str);
      //printf("%s", *(x+i)); // DEBUG
      hThreadArray[i] = (HANDLE)_beginthreadex(0, 0, isAlive, *(x+i), 0, &threadID);
      i++;
      }
  }

  WaitForMultipleObjects(i, hThreadArray, TRUE, INFINITE);
  fclose(infile);
  return 0;
}

何か考え/アイデアはありますか?

4

2 に答える 2

3

コードにはかなりの数の問題があります。特に、次の点に注意してください。

  1. WaitForMultipleObjectsの最初のパラメーターは、バッファーのサイズではなく、要素の数を取ります。代わりにline_numberを使用してください。

  2. hThreadArray [line_number]を介して設定する前に、line_numberを1にインクリメントするため、ループが配列の最初の要素(要素0)を設定することはありません。

  3. スレッドへのパラメーターとして、スタックに割り当てられたバッファー(line_buffer)へのポインターを渡します。次に、スレッドが開始する前に、このスタックバッファを変更し続けます。スレッド開始引数として送信されるパラメーターは、ヒープに割り当てる必要があります(スレッドごとに1つ、スレッドは後でそれを解放する責任があります)。

  4. _beginThreadExの応答コードを実際にチェックすることはないため、スレッドが開始されたかどうかを確実に知ることはできません。

  5. スレッドの先頭にprintfステートメントはありません。そこに1つ置くと、スレッドが開始されているかどうかをデバッグするのに役立ちます。

  6. サーバーへのHTTPパラメーターは失敗する可能性があります。実際のGETリクエストがどのように見えるかをWiresharkで確認し、それをコピーします。少なくとも、Hostヘッダー付きのHTTP/1.1を送信する必要があります。

  7. 最初にWSAStartup()を呼び出しても、WSACleanup()を呼び出さない新しいスレッドコードのパスがあります。

于 2013-01-28T07:07:28.443 に答える
1

メインスレッドが開始されたばかりのスレッドが何か有用なことをする前に、メインスレッドがループを続行するとどうなるかを考えてください。

それはでメモリを上書きします、それはline_bufferそれがすることです。これにより、スレッドがメモリを確認する前にメモリが変更されます。言い換えれば、このタイムラインを考慮してください。

main populates linebuffer
main starts thread 1
                               thread1 starts
main populates linebuffer
                               thread1 reads linebuffer

スレッドがバッファを確認する前に、バッファが変更されていることがわかります。

このようなスレッド間でデータを共有する場合は、スレッドがアクセスを適切にシリアル化することを確認する必要があります。これを行うにはいくつかの方法があり、そのうちのいくつかを以下に示します。

  • スレッドオブジェクトと同じように、ラインバッファを配列にします。これはmain、以前に送信されたものを上書きしないことを意味します。
  • スレッド間で何らかの形式の通信を使用してmainmainスレッドがローカルコピーを作成するまで待機してから続行します。

また、オブジェクト数としてWaitForMultipleObjects使用する必要があるかどうかもわかりません。sizeof(line_buffer)作成したオブジェクトの実際の数であるため、確かline_numberに良い選択です。

于 2013-01-28T07:06:00.567 に答える