質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.52%

  • C

    4517questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

c言語でサーバとプログラム間でのプログラムを作成したいのです。

受付中

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,450

monamona154

score 7

c言語でサーバとプログラム間でのプログラムを作成したいのです。
サーバを起動してクライアントが1~9の数字をどれかの数字を送信する→サーバが数字を受け取る→その送られた数字の段の九九をクライアントに送信して表示 というのを1つのサーバと2つ以上のクライアントを使用して作成したいです。
1~9の数字を打つと九九を表示する簡単なプログラムは出来るのですが、これをクライアントとサーバ間でやる方法がわかりません。
回答お願いします。

追記 tcpを使用したチャットプログラムを書きました 参考にして修正してもらいたいです

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define PORT 20007
#define BUF_SIZE 0x1000

 static void server(int port){
    struct sockaddr_in sin;
    fd_set rfds;
    int ld, sd[5], len, max,x,y;
    char *buf, str[256];

    if ((buf = malloc(BUF_SIZE)) == NULL) {
    perror("malloc");
    return;
    }

for(x=0;x<5;x++) sd[x] =  -1;

    if ((ld = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket");
    goto close_and_end;
    }

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    if (bind(ld, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
    perror("bind");
    goto close_and_end;
    }
    if (listen(ld, 3) < 0) {
    perror("listen");
    goto close_and_end;
    }

 loop:
    FD_ZERO(&rfds);
    FD_SET(ld, &rfds);
    max = ld;

for(x=0;x<5;x++){
    if (sd[x] >= 0) {
    FD_SET(sd[x], &rfds);
    if (max < sd[x]) max = sd[x];
    }
 }

    select(max + 1, &rfds, NULL, NULL, NULL);

for(x=0;x<5;x++){
    if (sd[x] > 0 && FD_ISSET(sd[x], &rfds)) {
    if ((len = read(sd[x], buf, BUF_SIZE)) > 0) {
        if (write(sd[x], buf, len) < 0) {
        close(sd[x]);
        sd[x] = -1;
        }
for(y=0;y<5;y++){
  if(x!=y){
        if (sd[y] > 0) {
        if (write(sd[y], buf, len) < 0) {
            close(sd[y]);
            sd[y] = -1;
        }
        }
  }
 }
    }
     else {
        if (len < 0) perror("read");
        close(sd[x]);
        sd[x] = -1;
    }
    }
 }

    if (FD_ISSET(ld, &rfds)) {
    int tmpd;

    len = sizeof(sin);
    if ((tmpd = accept(ld, (struct sockaddr*)&sin,   (socklen_t*)&len))
        < 0) {
        perror("accept");
        goto close_and_end;
    }
    inet_ntop(AF_INET, &sin.sin_addr.s_addr, str, sizeof (str));
    printf("connected from %s\n", str);

    if(sd[0]<0)
      sd[0]=tmpd;
    else if(sd[1]<0)
      sd[1]=tmpd;
    else if(sd[2]<0) 
      sd[2]=tmpd;
    else if(sd[3]<0) 
      sd[3]=tmpd;
    else if(sd[4]<0) 
      sd[4]=tmpd;
    else if(sd[5]<0) 
      sd[5]=tmpd;
    else{
      strcpy(buf, "Server too busy\n");
      send(tmpd, buf, strlen(buf), 0);
      close(tmpd);
    }
    }
    goto loop;

 close_and_end:
    for(x=0;x<5;x++){
    if (sd[x] >= 0) close(sd[x]);
    if (ld >= 0) close(ld);
    }

    free(buf);
}

 static void client(unsigned int ip, int port){
    struct sockaddr_in sin;
    char *buf;
    int sd, len, i;
    fd_set rfds;
    int max;

    if ((buf = malloc(BUF_SIZE)) == NULL) {
    perror("malloc");
    return;
    }

    if ((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket");
    goto close_and_end;
    }
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    sin.sin_addr.s_addr = htonl(ip);
    if (connect(sd, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
    perror("connect");
    goto close_and_end;
    }

loop:
    FD_ZERO(&rfds);
    max=1;

    if (0 < sd){
      FD_SET(sd, &rfds);
      if(max<sd) max = sd;
    }

    FD_SET(0, &rfds);

    select(max + 1, &rfds, NULL, NULL, NULL);

    if(FD_ISSET(0, &rfds)){
        if (fgets(buf, BUF_SIZE, stdin) <= 0)
        goto close_and_end;
        len = strlen(buf);
        if (send(sd, buf, len, 0) < 0) {
        perror("send");
        goto close_and_end;
        }
    }

    if(FD_ISSET(sd, &rfds)){
        len = recv(sd, buf, BUF_SIZE, 0);
        if (len <= 0) {
        if (len < 0) perror("send");
        goto close_and_end;
        }
        for (i = 0; i < len; i++) putchar(buf[i]);
    }
    goto loop;

 close_and_end:
    if (sd >= STDIN_FILENO) close(sd);
    if (sd >= 0) close(sd);
    free(buf);
}

 static void usage(void){
    printf("server mode: tcp2 -s\n");
    printf("client mode: tcp2 -c\n");
    exit(0);
}

 int main(int argc, char **argv, char **env){
    if (argc != 2) usage();
    if (argv[1][0] != '-') usage();
    switch (argv[1][1]) {
    case 's':
    server(PORT);
    break;
    case 'c':
    {
    struct hostent *ent;

    ent = gethostbyname("localhost");
    client(ntohl(*(int*)ent->h_addr_list[0]), PORT);
    break;
    }
    default:
    usage();
    }

    exit(0);
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • monamona154

    2016/07/01 15:31

    tcpのチャットのようなシステムでやりたいです。
    OSはlinuxで端末を複数使ってやりたいです。
    初心者なもので説明不足ですいません。他にも至らないところがあれば指摘してもらいたいです。

    キャンセル

  • cateye

    2016/07/01 18:58

    >OSはlinuxで端末を複数使って

    環境すべて(サーバやクライアント)がLinuxという認識でいいですか? で、”サーバ(Linux)につながっているクライアント(Linux)からみんなでチャットしたい”という事でしょうか? 

    キャンセル

  • monamona154

    2016/07/01 22:28

    そうです。
    それでクライアントから数字を打つと九九が出てくるようにしたいです。

    キャンセル

回答 4

+2

こんにちは。

Linuxネットワークプログラミングが参考になると思います。
Socketプログラミングは結構たいへんですが、上記サイトの解説はステップを踏んでいるので頑張ってみて下さい。

なお、質問をお見受けする限り、この分野の理解はあまり深くないように見えます。ですので、1つ1つ丁寧に進めることをお勧めします。急がば回れです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

まず1対1で実装してみましょう。その際、複数クライアントに対応する下準備として、送受信部分は別々に設計/実装したほうがいいでしょう。また、複数のクライアントに対応させるには、スレッドなりプロセスを起こす必要があると思うので、スレッド(プロセス)間でのデータの受け渡し方法等を考えたうえで、いつでも切り離せるようにしておきましょう。
「加筆」
通信そのものを確立するのも大事ですが・・・”切り離せるように”というのは以下のようなことに対応しやすいようにという事です。
・受信部は一か所で着信があったら、そのクライアント用のスレッドを起こす。(これも、データを受信して結果を送信するだけなのか、それともクライアントが切断するまでなのか?)
・応答部は送信するデータがあったらクライアントに送信する。(A,B,Cと3人のユーザがいる場合Aさんが入力したデータを受信したサーバはすべてのクライアント(B,C)に送るのか?・・・この方が楽w)
・送受信の排他制御はどうするか? (送受信ともキュー管理が必要と思われるので、キューの読み書き時に排他制御が必要です。・・・チャット・クライアントであれば、ユーザが入力中にデータを受信したらどうするか?)
とか、いろいろ考えることがありますね?・・・他の方も書かれていますが、1対多の通信の場合スレッド同士の排他制御がどうしても必要になります。とりあえず思いついたことなので話がごちゃ混ぜになってしまいますが・・・
送信データが発生したら送信キューに入れる。送信スレッド(?)は送信キューにデータがあったらそれを送信する。
受信部はデータを受信したら受信キューに入れる。受信データの処理をするスレッドは、受信キューにデータがあったらそれを取り出して処理をする。
・・・というような処理になると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

クライアントとサーバって、

ウェブを介しての方?
それとも、ただ単に2つのソフト間でデータの受け取りをしたいってこと?

あと、OS はなんでしょうか。

OS依存を無くしたやり方もあるかもしれませんが、
Windows API を使う方もあるので。

Windows なら EternlWindows の"ネットワーク" の "WinSock"とか、COMを使う方とか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

質問者さんの知識・技術で言えば、作ろうとしているもののハードルが高すぎると思います。
まず HTTP クライアントを作りましょう。特定のサイトからページソースを取ってくるのが目標です。
それができたら HTTP サーバーを作りましょう。
もちろん、ポート 80 やポート 8080 は競合すると思うので、別のポートを使ってください。
先ほど作ったクライアントで動作確認できるはずです。
そこまで行けば、目標のソフトの 9 割方は出来たも同然だと思います。

追記

単純な 1 対 1 のクライアント・サーバーで、サーバーの役目は九九の答えを返すだけだと思っていたので、9 割型と書きましたが、多対一でチャット機能が付くとなると話は別です。スレッドセーフなコーディングも勉強しなくてはなりません。これも結構厄介なカテゴリですが、頑張ってください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • C

    4517questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。