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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

Q&A

解決済

1回答

1335閲覧

TCP型クライアントで入力した文字列をサーバで計算してクライアントに返すプログラミングが分かりません

mercury

総合スコア11

C

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

0グッド

1クリップ

投稿2019/05/17 08:33

編集2019/05/17 10:51

TCP型クライアントで入力した文字列をサーバで計算してクライアントに返すというプログラミングが分かりません。サーバ側だけ変更すればいいのでどこをどうしたらいいか教えていただきたいです。strtok関数等を使うというところまではわかるのですが・・・

c

1#include <winsock.h> 2#include <stdio.h> 3#include <stdlib.h> 4#include <string.h> 5#include <ctype.h> 6 7#pragma comment(lib,"wsock32.lib") 8 9#define MAX_BUFF_12A 1024 10 11int ServerPort = 10010; 12 13 14int main( void ) 15{ 16 char StrBuf[128] ; 17 int rVal; 18 SOCKADDR_IN local, from; 19 WSADATA wsaData ; 20 SOCKET listen_socket; //Listen用ソケット 21 SOCKET DataSocket; //送受信用ソケット 22 WORD wVersionRequested ; 23 int fromlen = sizeof( from ) ; 24 25 26 27 printf("サーバ起動時のポート番号(1024以上):"); scanf("%d", &ServerPort); 28 29 30 31 32 wVersionRequested = MAKEWORD( 1, 1 ); 33 rVal = WSAStartup( wVersionRequested, &wsaData ); 34 if(rVal != 0 ) { 35 printf("エラー:ソケット初期化・・・終了します\n"); 36 WSACleanup(); 37 return(-1); 38 } 39 40 local.sin_family = AF_INET ; 41 local.sin_addr.s_addr = INADDR_ANY ; 42 local.sin_port = htons( (unsigned short)ServerPort ); 43 44 45 listen_socket = socket( AF_INET, SOCK_STREAM, 0 ) ; 46 if( listen_socket == INVALID_SOCKET ) { 47 printf("エラー:ソケット生成・・・終了します\n"); 48 WSACleanup(); 49 return(-1); 50 } 51 52 53 if( bind( listen_socket, (struct sockaddr*)&local, sizeof(local) ) 54 == SOCKET_ERROR) { 55 printf("エラー:バインドbind・・・終了します\n"); 56 WSACleanup(); 57 return(-1); 58 } 59 printf("******サーバの起動*****\n"); 60 61 listen( listen_socket, 5 ); 62 printf("ポート番号%dをlistning中(接続待ち)...", ServerPort ); 63 64 DataSocket = accept( listen_socket, (struct sockaddr*)&from, &fromlen ); 65 printf("\nサーバ=%s, ポート番号=%dに接続.\n\n", 66 inet_ntoa(from.sin_addr), htons(from.sin_port) ) ; 67 68 69 70 71 /******** データの受信 ********/ 72 while (1) { 73 rVal = recv(DataSocket, StrBuf, sizeof(StrBuf), 0); 74 StrBuf[rVal] = '\0'; 75 76 if (rVal == SOCKET_ERROR || rVal == 0) { 77 printf("エラー:相手からの切断されました\n・・・終了します\n"); 78 break; 79 } 80 if (StrBuf == '.') 81 break; 82 83 /******** 受信したデータ(文字列)をホスト画面に表示 *********/ 84 printf("%s\n", StrBuf); 85 86 /******** 文字列の送信 *********/ 87 send(DataSocket, StrBuf, (int)strlen(StrBuf), 0); 88 89 } 90 91 92 // ソケット終了処理 93 closesocket( DataSocket ); 94 WSACleanup(); 95 96 printf("\n\nEnterキーを1,2回押してプログラム終了"); 97 getchar(); 98 getchar(); 99 100 return(0); 101} 102
#include <winsock.h> //Windows用ソケットライブラリ用 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #pragma comment(lib,"wsock32.lib") //WinSockライブラリをリンク #define MAX_BUFF_12A 1024 // バッファの長さ int NetPortNo = 10010; char HostAddr[50] = "127.0.0.1"; // // main // int main( void ) { char StrBuf[MAX_BUFF_12A+1] ; char szHost[MAX_BUFF_12A+1]; SOCKET DataSocket; WSADATA wsaData; SOCKADDR_IN server; HOSTENT *hostEnt; int rVal; WORD wVersionRequested; unsigned int addr; // ソケットの初期化(ウィンドウズ用Winsockの初期化) wVersionRequested = MAKEWORD( 1, 1 ); rVal = WSAStartup( wVersionRequested, &wsaData ); //初期化の関数 if(rVal != 0 ) { //初期化のエラー printf("エラー:ソケット初期化・・・終了します\n"); WSACleanup(); return(-1); } // ソケット生成(TCPソケット) DataSocket = socket( AF_INET, SOCK_STREAM, 0 ) ; // ソケット生成の関数 if( DataSocket < 0 ) { printf("エラー:ソケット生成・・・終了します\n"); return(-1);} printf("サーバのホスト名(またはIPアドレス):"); scanf("%s",HostAddr); printf("サーバのポート番号:"); scanf("%d",&NetPortNo); strcpy( szHost, HostAddr ); if( isalpha( szHost[0] ) ) { hostEnt = gethostbyname( szHost ); } else { addr = inet_addr( szHost ); hostEnt = gethostbyaddr( (char*)&addr, 4, AF_INET ); } if( hostEnt == NULL ) { printf("エラー:アドレスを解決不能[%s]\n・・終了!\n", szHost);return(-1); } printf("******クライアントの起動*****\n"); // サーバ接続のための初期化 memset( &server, 0, sizeof(server) ); memcpy( &(server.sin_addr), hostEnt->h_addr, hostEnt->h_length ); server.sin_family = hostEnt->h_addrtype; server.sin_addr.s_addr = *(( unsigned long*)hostEnt->h_addr ); //サーバアドレス server.sin_port = htons( (unsigned short)NetPortNo ); // サーバのポート番号の設定 <---------- ポート! // サーバへ接続を試みる(connect関数) printf("サーバ[%s]へ接続中...", szHost ) ; if( connect( DataSocket,(struct sockaddr*)&server, sizeof(server) ) == SOCKET_ERROR) { printf("エラー:サーバへの接続(connect)\n・・・終了します\n"); return(-1); } printf("%sに接続完了しました\n", szHost ); /******** 文字列のキーボードからの読込み *********/ while (1) { printf("文字列を入力:"); scanf("%s", StrBuf); getchar(); /******** 文字列の送信 *********/ send(DataSocket, StrBuf, (int)strlen(StrBuf), 0); //送信(send関数) if (StrBuf[0] == '.') break; /******** データの受信 ********/ rVal = recv(DataSocket, StrBuf, sizeof(StrBuf), 0); //受信(recv関数) StrBuf[rVal] = '\0'; //受信したデータ(文字列)の最後にNULL文字付加 if (rVal == SOCKET_ERROR || rVal == 0) { //受信時エラー(または切断) printf("エラー:相手からの切断されました\n・・・終了します\n"); break; } printf("受信文字列:%s\n", StrBuf); } // ソケット終了処理 closesocket( DataSocket ); //ソケットのクローズ WSACleanup(); //ソケットの破棄 printf("\n\nEnterキーを1,2回押してプログラム終了"); getchar(); getchar(); return(0); }

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2019/05/17 08:42

> 文字列をサーバで計算して どんな文字列を計算してどう返すのでしょう. 具体例がありましたら追記をお願い致します.
mercury

2019/05/17 08:51

返信ありがとうございます。大事な所が抜けていました申し訳ないです。 具体的には「add,30,10」,「sub,40,10」など「,」で3つに区切られた四則演算ができるものです。
jimbe

2019/05/17 09:09 編集

「add,30,10」が来たら「40」, 「sub,40,10」が来たら「30」を返すことになるのでしょうか. 四則演算ということは 乗除もあるわけですが, その場合の最初のキーワードは "mul" と "div" でしょうか. 計算できない文字列だった場合(キーワードが加減乗除では無かったり, 数値が文字だったり, 0割だったり等々)は考慮が必要ですか? 考慮する場合, 何を返せば良いのでしょうか. 計算は > /******** 受信したデータ(文字列)をホスト画面に表示 *********/ > printf("%s\n", StrBuf); と > /******** 文字列の送信 *********/ > send(DataSocket, StrBuf, (int)strlen(StrBuf), 0); の間で, StrBuf の式を計算して StrBuf に入れ直す(もしくは別に文字列を作る)形となるのでしょうか.
mercury

2019/05/17 09:11

出力例を確認しました。クライアント側に返された時には「add,30,10」が入力された場合には、「30+10=40」と返すようになっています。乗除の場合は仰る通りのキーワードです。 計算できない文字列だった場合「”入力された文字列”の計算はできません」と表示したいです。(入力された文字列にはそのまま「abc,30,10」など間違った文字列を入れたい) 計算方法はおそらくjimbe様の提案された形になるかと思います
jimbe

2019/05/17 09:29

数値部分に関しましては何か指示はありましたでしょうか. 整数のみであったり, 少数, 負数, 桁数等ですが.
mercury

2019/05/17 09:33

整数のみ計算できれば良いようでした。桁数の指定はありませんでした
dodox86

2019/05/17 09:54

TCP通信の部分はできるはずなのでそこはもう問題ではなくて、計算が正しくできるようになれば本質問の目的は達成できる、と言うことしょうか。
mercury

2019/05/17 10:06

はい。送受信はできるのでサーバ側で計算をしてそれをクライアント側に返したいのです
otn

2019/05/17 17:42

strtokの使い方のどこが分からないのか、具体的に書いてください。
guest

回答1

0

ベストアンサー

以下の calc を該当箇所で呼び出すのは如何でしょうか.

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <ctype.h> 5 6int to_long(char *s, long *v) { 7 char *endptr; 8 if(s == NULL) return 0; 9 *v = strtol(s, &endptr, 10); 10 return *endptr == '\0'; 11} 12 13void calc(char *buf) { 14 char *fomula = (char *)malloc(strlen(buf)+1); 15 strcpy(fomula, buf); 16 //異常を発見して break した場合はこれが返る 17 sprintf(buf, "\"%s\"の計算はできません", fomula); 18 do { 19 long v1, v2; 20 21 char *operation = strtok(fomula, ","); 22 if(operation == NULL) break; 23 24 if(!to_long(strtok(NULL, ","), &v1)) break; 25 if(!to_long(strtok(NULL, ","), &v2)) break; 26 27 if(!strcmp(operation, "add")) { 28 sprintf(buf, "%d+%d=%d", v1, v2, v1+v2); 29 } else if(!strcmp(operation, "sub")) { 30 sprintf(buf, "%d-%d=%d", v1, v2, v1-v2); 31 } else if(!strcmp(operation, "mul")) { 32 sprintf(buf, "%d*%d=%d", v1, v2, v1*v2); 33 } else if(!strcmp(operation, "div")) { 34 if(v2 == 0) break; //0割り回避 35 sprintf(buf, "%d/%d=%d", v1, v2, v1/v2); 36 } 37 } while(0); 38 //必ずココを通ること 39 free(fomula); 40} 41 42int main() { 43 char StrBuf[128]; 44 45 strcpy(StrBuf, ""); 46 calc(StrBuf); 47 printf("%s\n", StrBuf); 48 49 strcpy(StrBuf, "a"); 50 calc(StrBuf); 51 printf("%s\n", StrBuf); 52 53 strcpy(StrBuf, "add"); 54 calc(StrBuf); 55 printf("%s\n", StrBuf); 56 57 strcpy(StrBuf, "add,"); 58 calc(StrBuf); 59 printf("%s\n", StrBuf); 60 61 strcpy(StrBuf, "add,,"); 62 calc(StrBuf); 63 printf("%s\n", StrBuf); 64 65 strcpy(StrBuf, "add,,,"); 66 calc(StrBuf); 67 printf("%s\n", StrBuf); 68 69 strcpy(StrBuf, "add,30,10"); 70 calc(StrBuf); 71 printf("%s\n", StrBuf); 72 73 strcpy(StrBuf, "sub,40,10"); 74 calc(StrBuf); 75 printf("%s\n", StrBuf); 76 77 strcpy(StrBuf, "mul,40,10"); 78 calc(StrBuf); 79 printf("%s\n", StrBuf); 80 81 strcpy(StrBuf, "div,40,0"); 82 calc(StrBuf); 83 printf("%s\n", StrBuf); 84 85 strcpy(StrBuf, "div,40,10"); 86 calc(StrBuf); 87 printf("%s\n", StrBuf); 88 89 return 0; 90}

投稿2019/05/17 10:11

編集2019/05/17 11:54
jimbe

総合スコア12632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mercury

2019/05/17 11:00

自分でやってみたのですがうまくいきませんでした・・・クライアント側のソースコードも追記したので、もしよろしければサーバ側のコードは最後どうなるか見せて頂くことはできないでしょうか
jimbe

2019/05/17 11:06

サーバのファイルに to_long 関数と calc 関数をコピペしまして, 以下のように呼び出しを追加すれば良いはずですが... /******** 受信したデータ(文字列)をホスト画面に表示 *********/ printf("%s\n", StrBuf); calc(StrBuf); //追加 /******** 文字列の送信 *********/ send(DataSocket, StrBuf, (int)strlen(StrBuf), 0); 「うまくいきませんでした」では何が起きたのか分かりません. 何が起きたのでしょうか.
mercury

2019/05/17 11:17

私のコピペする位置が間違っているのだと思いますがクライアント側から文字列を入力しても何も変わらず入力した文字列が帰ってきていました。
jimbe

2019/05/17 11:41

calc 関数の呼び出しを追加した上で, 関数のコピペに失敗していれば, 何かコンパイルエラー等ありそうですが, コンパイルは成功したのでしょうか.
jimbe

2019/05/17 11:44

なお, 私のパソコンにはCコンパイラは入っていません. オンラインのCコンパイラサイトを使っていますので, ネットワーク関係のコードは実行できないと思います.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問