マルチスレッドのサーバー作り

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
スモモ

マルチスレッドのサーバー作り

#1

投稿記事 by スモモ » 15年前

[1] 質問文
 [1.1] 自分が今マルチプロセッサのサーバー作りたいです。
 [1.2] 取り組んだプログラムコードが下にあります。
 [1.3] 複数クライアント対応作るつもりですが複数対応なってないです。
 [1.4] どうすれば複数クライアントが扱えるサーバーがどのように作ればいいでしょうか?
[2] 環境  
 [2.1] OS : Windows
 [2.2] コンパイラ名 : VC++ 2008
[3] その他
 ・C言語を一年半ぐらい勉強しました。初級か中級ぐらいです。
 ・ライブラリを使っていません。
#include <process.h>
#include <winsock2.h>

#pragma comment(lib,"WSOCK32")
#pragma warning(disable:4312)

class C_server{
    int        dstSocket;
    static    void CallFunc( LPVOID pParam );
public:
    C_server(int dstSocket);
    void    MainFunc();
};

C_server::C_server(int dstSocket):dstSocket(dstSocket){_beginthread(CallFunc,0,this);}
void C_server::CallFunc(LPVOID pParam){((C_server*)pParam)->MainFunc();}
void C_server::MainFunc(){
    char buffer[1024];
    while(dstSocket){
        //パケットの受信
        int numrcv = recv(dstSocket, buffer, sizeof(char)*1024, 0);
        if(numrcv ==0 || numrcv ==-1){
            closesocket(dstSocket);
            break;
        }
        printf("変換前 %s",buffer);
        for (int i=0; i< numrcv; i++){ // bufの中の小文字を大文字に変換
            buffer = toupper(buffer);
        }
        // パケットの送信
        send(dstSocket, buffer, sizeof(char)*1024, 0);
        printf("→ 変換後 %s \n",buffer);
    }
}

void main()
{
    // ポート番号,ソケット
    int srcSocket;  // 自分
    int dstSocket;  // 相手

    // sockaddr_in 構造体
    struct sockaddr_in srcAddr;

    // Windows の場合
    WSADATA data;
    WSAStartup(MAKEWORD(2,0), &data);
    // sockaddr_in 構造体のセット
    memset(&srcAddr, 0, sizeof(srcAddr));
    srcAddr.sin_port = htons(40453);
    srcAddr.sin_family = AF_INET;
    srcAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    // ソケットの生成(ストリーム型)
    srcSocket = socket(AF_INET, SOCK_STREAM, 0);
      // ソケットのバインド
    bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr));
      // 接続の許可
    listen(srcSocket, 10);

    while(1){
        if((dstSocket = accept(srcSocket, NULL, 0))>0){
            //static C_server s(dstSocket);    //
            new C_server(dstSocket);        //
            //C_server s(dstSocket);        //
        }
    }
    WSACleanup();
}


ご教授の程、よろしくお願いします。 画像

Poco

Re:マルチプロセッサのサーバー作り

#2

投稿記事 by Poco » 15年前

マルチスレッドプログラミングになります。

accept()後にスレッドを生成し、それにdstSocketを渡してください。

#タイトルから判断するに、マルチプロセスで処理したいようにも
#見えますが、Windowsってできましたっけ?
#不可能か、結構面倒だったので諦めた覚えがあります。
画像

スモモ

Re:マルチプロセッサのサーバー作り

#3

投稿記事 by スモモ » 15年前

ぽこさん


ご回答ありがとうございます。

> accept()後にスレッドを生成し、それにdstSocketを渡してください。

おっしゃる通りやっていると思いますが、よくわからないです。

よければ、詳しく教えていただけないでしょうか。


> #タイトルから判断するに、マルチプロセスで処理したいようにも

> #見えますが、Windowsってできましたっけ?

> #不可能か、結構面倒だったので諦めた覚えがあります。

よくわからないです。

わかるまで、マルチスレッドプログラミングとして覚えます。

ご指摘いただき、ありがとうございました。

softya

Re:マルチプロセッサのサーバー作り

#4

投稿記事 by softya » 15年前

大雑把に説明しますね。
サーバー処理は、通用マルチスレッドあるいはマルチプロセスで処理します。これは、マルチプロセッサ(マルチコア含む)であることとは無関係です。
サーバーとクライアントが通信待ちしている間CPUは事実上Sleep状態になっていてCPUパワーの資源は無駄に使われていない状態と言えます。そこで、その無駄な時間を出来るだけ減らすために同時に復数のクライアントと通信をするための工夫がマルチスレッドあるいはマルチプロセスです。

ちなみにスモモさんのコードはマルチスレッドやマルチプロセスは一切行われていません。

有名なApache HTTP Serverの動作が書かれています。
http://ja.wikipedia.org/wiki/Apache_HTTP_Server

まず、マルチプロセスやマルチスレッドに付いて学ばれてはどうでしょう。
※ マルチプロセッサの負荷分散に付いてはOS任せにするのが一番です。マルチプロセスやマルチスレッドを使えば自動的にプロセッサを振り分けてくれますので気にしなくて良いです。

マルチプロセスの例。ただし、この人はスレッドの方が良いと言ってますが。
http://abtc.cocolog-nifty.com/tips/2005 ... _f286.html
TCP/IP通信 _beginthreadexでスレッドを使用。
http://7ujm.net/C++/SDKTCP.html

スモモ

Re:マルチプロセッサのサーバー作り

#5

投稿記事 by スモモ » 15年前

softyaさん


ご丁寧に説明いただきありがとうございます。

それなのに、少ししかわからなくでごめんなさい!

もっと勉強する必要と思いますが。

とりあえず、クライアント50ぐらい同時に処理できるサーバーが作りたいです。

アドバイス参照しながら、やっていきます。

もし、よければ、もっとアドバイス下さい。

softya

Re:マルチプロセッサのサーバー作り

#6

投稿記事 by softya » 15年前

アドバイスはOKですが、何が分からないか整理してもらえますか。
>それなのに、少ししかわからなくでごめんなさい!
何がわかって、何が自分で調べても理解できなかったかできるだけ細かく整理出来ていると説明ポイントが絞りやすく良いですね。
マルチスレッドについて詳しく説明しようと思ったら、OS全般のことを説明することになり内容が本一冊分ってこともありえます。なので、とてもここで説明しきれませんので本を紹介することになると思います。

dic

Re:マルチプロセッサのサーバー作り

#7

投稿記事 by dic » 15年前

>マルチプロセッサ
まずはこの単語の意味から調べてください
次にWindowsのCPUの使われ方を調べてください

スモモ

Re:マルチプロセッサのサーバー作り

#8

投稿記事 by スモモ » 15年前

softyaさん


ご親切にしてもらってありがとうございます。

> >それなのに、少ししかわからなくでごめんなさい!

の意味は

したいことを聞いたら、したいことだけでなく、他にも理解しないといけないことが多くなりました。

すべてを学ぶのは時間かかることと、

自分、時間がないと自分をどうしようもないところを追い詰めたことだと思います。

自分が未熟のせいです。

softyaさんは気にしないでください。

よかったら、自分が書いたコード(上にあります)見てもらってもいいでしょうか。

なぜ、クライアント1つしか処理できない教えてもらってもいいでしょうか。

Poco

Re:マルチプロセッサのサーバー作り

#9

投稿記事 by Poco » 15年前

> なぜ、クライアント1つしか処理できない教えてもらってもいいでしょうか。

accept()の後、つまりユーザから接続を受けた後から C_serverクラスのコンストラクタ内の処理の間、
ユーザから接続を待っていないからです。
並列に処理を行ないたいのなら、ユーザからの接続を受けた後、スレッドを作成し、
すぐに接続待ち(accept()呼び出し)に戻る必要があります。
生成されたスレッドの中で、C_serverクラスのコンストラクタ内の処理相当のことをすれば、OKです。

スモモ

Re:マルチスレッドのサーバー作り

#10

投稿記事 by スモモ » 15年前

dicさん


書き込みありがとうございました。

> >マルチプロセッサ

> まずはこの単語の意味から調べてください

> 次にWindowsのCPUの使われ方を調べてください

お恥ずかしいところ見せちゃってすいません。

調べてみます。

スモモ

Re:マルチスレッドのサーバー作り

#11

投稿記事 by スモモ » 15年前

ぽこさん


ご親切に回答してもらって、ありがとうございます。

コード書き直してみます。

dic

Re:マルチスレッドのサーバー作り

#12

投稿記事 by dic » 15年前

配列は扱えますか?

//=======================================================
Windowsで動くソースは持ってますし、動作の確認もできました
運営したいのですが、時間の都合上できない状態です
ちなみに私の持っているソースはサーバ側はシングルスレッドで処理してます
ネット上の知り合いになりますが、20~30人接続してもラグが発生しないようです
なかなか知名度が低く、これ以上のクライアント(ユーザ)を確保できないので
性能の指標は未知数です

Poco

Re:マルチスレッドのサーバー作り

#13

投稿記事 by Poco » 15年前

> 配列は扱えますか?
>
> ちなみに私の持っているソースはサーバ側はシングルスレッドで処理してます
> ネット上の知り合いになりますが、20~30人接続してもラグが発生しないようです

selectやpollを使っているんですか?

dic

Re:マルチスレッドのサーバー作り

#14

投稿記事 by dic » 15年前

>selectやpollを使っているんですか?
ソケット通信までとしか都合上言えないです

スモモ

Re:マルチスレッドのサーバー作り

#15

投稿記事 by スモモ » 15年前

みなさん


ご協力ありがとうございます。

自分もよくわからないですが、できました。みなさんのおかげです。

いろいろやってみたら、上のコードとほとんど変わらないですが、できるようになりました。

どなた、わかっている方、ご教授の程、よろしくお願いします。

コードは以下のようになります。
/*
    S/2010/08/03    ServerTest00.h
    E/2010/08/15    ServerTest23.h
*/
#include <stdio.h>
#include <process.h>
#include <winsock2.h>

#pragma comment(lib,"WSOCK32")

#define    MAX    3
#define PORT    1234
//
class C_server{
    int        dstSocket;  // 相手
    char    *name;
    static    void CallFunc( LPVOID pParam );
public:
    static int cnt;
    C_server();
    C_server(int dstSocket,char *name);
    void    step();
};

int C_server::cnt = 0;
C_server::C_server(){dstSocket = 0;}
C_server::C_server(int dstSocket,char *name):dstSocket(dstSocket),name(name){_beginthread(CallFunc,0,this);}
void C_server::CallFunc(LPVOID pParam){((C_server*)pParam)->step();}
void C_server::step(){
    char buffer[1024];
    cnt++;
    int NO = cnt;
    printf("%d 個クライアントが接続している\n",cnt);
    while(1){
        //パケットの受信
        int numrcv = recv(dstSocket, buffer, sizeof(char)*1024, 0);
        if(numrcv ==0 || numrcv ==-1){
            closesocket(dstSocket);
            cnt--;
            printf("NO.%d 接続切れた %d 個クライアントが接続している\n",NO,cnt);
            break;
        }
        printf("NO.%d %s 変換前 %s",NO,name,buffer);
        for (int i=0; i< numrcv; i++){ // bufの中の小文字を大文字に変換
            buffer = toupper(buffer);
        }
        // パケットの送信
        send(dstSocket, buffer, sizeof(char)*1024, 0);
        printf("→ 変換後 %s \n",buffer);
    }
}

//
void main()
{
    // ポート番号,ソケット
    int srcSocket;  // 自分
    int dstSocket;  // 相手

    // sockaddr_in 構造体
    struct sockaddr_in srcAddr;
    struct sockaddr_in dstAddr;

    // Windows の場合
    WSADATA data;
    WSAStartup(MAKEWORD(2,0), &data);
    // sockaddr_in 構造体のセット
    memset(&srcAddr, 0, sizeof(srcAddr));
    srcAddr.sin_port = htons(PROT);
    srcAddr.sin_family = AF_INET;
    srcAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    // ソケットの生成(ストリーム型)
    srcSocket = socket(AF_INET, SOCK_STREAM, 0);
      // ソケットのバインド
    bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr));
      // 接続の許可
    listen(srcSocket, MAX + 1/*(int)0x8ffffff*//*1*/);

    while(1){
        int dstAddrsize = sizeof(dstAddr);
        // 接続の受付け
        printf("接続を待っています\nクライアントプログラムを動かしてください\n");
        if((dstSocket = accept(srcSocket, (struct sockaddr *) &dstAddr, &dstAddrsize))>0){
            if(C_server::cnt >= MAX){
                printf("接続最大数 %d を超えた\n",MAX);
                continue;
            }
            printf("%s から接続を受けました\n", inet_ntoa(dstAddr.sin_addr));
            new C_server(dstSocket,inet_ntoa(dstAddr.sin_addr));            //
        }
    }
    WSACleanup();
}



ご教授の程、よろしくお願いします。

dic

Re:マルチスレッドのサーバー作り

#16

投稿記事 by dic » 15年前

新手の釣りでしょうか?

スモモ

Re:マルチスレッドのサーバー作り

#17

投稿記事 by スモモ » 15年前

dicさん


書き込みありがとうございます。

> 新手の釣りでしょうか?

の意味わからないですが、教えていただけないでしょうか?

softya

Re:マルチスレッドのサーバー作り

#18

投稿記事 by softya » 15年前

まったくスレッドを使っていないので絶対に目的が達成されていないのに「できました」と書かれていたからだと思います。スレッドを使っていないのはなぜでしょうか?
それと時間がないのに、こんなに悠長にしていて大丈夫ですか? 画像

Coca

Re:マルチスレッドのサーバー作り

#19

投稿記事 by Coca » 15年前

C++を使用したことがないので、質問になりますが、
メインスレッド内、newで確保した領域を解放する必要があると思いますが、その点は問題ありませんか?
後は定型文みたいなものですから、_beginthreadの運用としてはいいのではないでしょうか。

_beginthreadのせいと思わしき問題が出るけど、俺のテスト項目のことだから、まぁいっかw 画像

Poco

Re:マルチスレッドのサーバー作り

#20

投稿記事 by Poco » 15年前

> softyaさん
> まったくスレッドを使っていないので絶対に目的が達成されていないのに

一応コンストラクタの所で_beginthread()を呼び出していますよ。

>スモモさん
やりたいことは達成出来たのですよね?
他に何が問題/疑問なのでしょうか?

softya

Re:マルチスレッドのサーバー作り

#21

投稿記事 by softya » 15年前

>一応コンストラクタの所で_beginthread()を呼び出していますよ。
失礼しました。
じゃあ。問題ないはずですからテストをして問題ないことを確認してくださいとしか言えません。

スモモ

Re:マルチスレッドのサーバー作り

#22

投稿記事 by スモモ » 15年前

みなさん


ご協力ありがとうございます。


おかげで解決しました。


またよろしくお願いします。

閉鎖

“C言語何でも質問掲示板” へ戻る