ページ 11

ソケットプログラミングの基礎問題

Posted: 2013年6月16日(日) 15:08
by ツンドラ
はじめまして。
学校にてUNIXを用いてのソケットプログラミングをゼロから学んでいます。
自宅で課題をやろうと思いwindowsPCにvirtualboxを導入しようとしたところ、何か間違っているようで成功しませんでした。
そこで、こちらに質問し、添削をして頂こうと考えました。

課題にそって、手探りながらもソースを組んでみたため、添削をお願いします。

課題内容
・クライアント、サーバを作り、クライアントで入力した小文字をサーバに送り、サーバが大文字に変換、その大文字をクライアントに送り返す。
補足
・終了条件を付けるなどの支持は一切なし。

クライアント側

コード:

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

#define SOCK_NAME "./socket"

/*argv[1]はIPアドレス, argv[2]はポート番号*/

int main(int argc, char *argv[])
{
	struct sockaddr_in saddr;
	int soc;
	char buf[1024];

	char *sIP;
	int sPort;

	sIP = argv[1];			//サーバのIPアドレスを取得
	sPort = atoi(argv[2]);	//ポート番号を取得

	/*ソケット作成*/

	if ( (soc = socket(AF_INET, SOCK_STREAM, 0) ) < 0 )
	{
		perror("socket");
		exit(1);
	}

	memset((char *)&saddr, 0, sizeof(saddr));	//saddrを0で埋める
	saddr.sin_family = AF_INET;					//アドレスファミリ
	saddr.sin_addr.s_addr = inet_addr(sIP);		//サーバのIPアドレス
	saddr.sin_port = htons(sPort);				//サーバのポート番号

	/*接続*/

	if( connect(soc, (struct sockaddr *)&saddr, sizeof(saddr) ) < 0)
	{
		perror("connect");
		exit(1);
	}

	/*小文字→大文字に変換*/

	printf("小文字を入力して下さい\n");

	while( fgets(buf, 1024, stdin) ) //キーボードから文字入力
	{
		write(soc, buf, 1024);
		read(soc, buf, 1024);

		printf("大文字に変換します\n%s\n\n", buf);
		printf("小文字を入力して下さい\n");
	}
	close(soc);
	return 0;
}
サーバ側

コード:

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

#define SOCK_NAME "./socket"

/*argv[1]はポート番号*/

int main(int argc, char *argv[])
{
	int i;
	int fd1, fd2;//ソケット
	struct sockaddr_in saddr;
	struct sockaddr_in caddr;

	int sPort;

	int len;//クライアントのアドレス構造体の長さ
	int ret;//大文字変換の時に使用
	char buf[1024];

	sPort = atoi(argv[1]);	//ポート番号を取得

	/*ソケット作成*/

	if( (fd1 =socket(AF_INET, SOCK_STREAM, 0)) < 0 )
	{
		perror("socket");
		exit(1);
	}

	memset((char *)&saddr, 0, sizeof(saddr));	//構造体を0で埋める
	saddr.sin_family = AF_INET;					//アドレスファミリ
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);	//ワイルドカードを使用
	saddr.sin_port = htons(sPort);				//ポート番号


	if( bind( fd1, (struct sockaddr *)&saddr, sizeof(saddr) ) < 0)
	{
		perror("bind");
		exit(1);
	}

	if( listen(fd1,5) < 0 )
	{
		perror("listen");
		exit(1);
	}

	while(1)
	{
		len = sizeof(caddr);//入出力パラメータのサイズをセット

		if( ( fd2 = accept(fd1, (struct sockaddr *)&caddr, &len) ) < 0)
		{
			perror("accept");
			exit(1);
		}

		while( (ret = read(fd2, buf, 1024)) > 0 )//retに文字数を格納
		{
			for (i=0; i < ret; i++)
			{
				if (isalpha(buf[i]))	//文字かどうか判定
				{
					buf[i] = toupper(buf[i]);
				}
			}
			write(fd2, buf, 1024);
		}
		close(fd2);
	}
	close(fd1);

	return 0;
}
理想の動作
括弧はキーボードからの入力なのか、プログラム側の出力側なのかを表しています。

クライアント側(実行ファイル名client, 自分のPCのIPアドレス192.168.1.3)

#client 10000 192.168.1.3  (入力)
#小文字を入力して下さい  (出力)
#abcdefg            (入力)
#大文字に変換します     (出力)
#ABCDEFG           (出力)
#
#小文字を入力して下さい  (出力)
#

となる動作が理想です。

私の組んだソースに間違いや直した方が良い部分はありますでしょうか?
添削よろしくお願いします。

Re: ソケットプログラミングの基礎問題

Posted: 2013年6月16日(日) 16:34
by h2so5
どのように成功しないのか具体的に書いてください。
何かエラーは表示されたのでしょうか。
また、サーバーとクライアントを動かしているのは同じマシンなのか、
192.168.1.3は仮想マシンのホスト側のアドレスなのかゲスト側アドレスなのかという事も明確にしてください(ブリッジなら同一だと思いますが)。

ソースをざっと見たところ気になるのは、何文字入力しても必ず1024文字送信してしまっていることです。

Re: ソケットプログラミングの基礎問題

Posted: 2013年6月16日(日) 16:49
by ツンドラ
h2so5 さんが書きました:どのように成功しないのか具体的に書いてください。
何かエラーは表示されたのでしょうか。
また、サーバーとクライアントを動かしているのは同じマシンなのか、
192.168.1.3は仮想マシンのホスト側のアドレスなのかゲスト側アドレスなのかという事も明確にしてください(ブリッジなら同一だと思いますが)。

ソースをざっと見たところ気になるのは、何文字入力しても必ず1024文字送信してしまっていることです。
成功しなかったはプログラムではなく、virtualboxの導入です。
導入に失敗したため、自宅のPCでこのプログラムが実行できませんでした。

そこでこちらに質問し、プログラムにおかしな部分がないかどうかを添削して頂きたいと思いました。
言葉足らずで上手く伝わらず申し訳ありません。

サーバとクライアントは同じマシンで動かしています。
学校で使用しているPCでは、UNIXを使い、ktermで別ウインドウを立ち上げ、それぞれをクライアント、サーバとしてプログラムを実行します。

>>192.168.1.3は仮想マシンのホスト側のアドレスなのかゲスト側アドレスなのかという事も明確にしてください(ブリッジなら同一だと思いますが)。
というのは、192.168.1.3はサーバのIPアドレスなのかクライアントのIPアドレスなのかということでしょうか?
申し訳ありません。私の勉強不足で意図していることが読み取れませんでした。

やはりクライアントから、何文字であっても1024文字送信するのは制限した方が良いのでしょうか?
これはエラーが発生しますか?

Re: ソケットプログラミングの基礎問題

Posted: 2013年6月16日(日) 17:18
by h2so5
ツンドラ さんが書きました: 成功しなかったはプログラムではなく、virtualboxの導入です。
導入に失敗したため、自宅のPCでこのプログラムが実行できませんでした。

そこでこちらに質問し、プログラムにおかしな部分がないかどうかを添削して頂きたいと思いました。
言葉足らずで上手く伝わらず申し訳ありません。
僕もちゃんと読んでいませんでした。失礼しました。
ツンドラ さんが書きました: やはりクライアントから、何文字であっても1024文字送信するのは制限した方が良いのでしょうか?
これはエラーが発生しますか?
エラーは出ませんが、余分なデータを送るのは無駄ではないかと思いました。
ただ、可変長にすると少し複雑になってしまうので入門としてはこれでよいのかも知れません。
そのかわり、サーバー側で終端文字があったときにそこで変換を打ち切るという工夫は出来そうです。

あとコマンドライン引数のチェックもしたほうが親切です。

僕の環境 (Ubuntu 12.04)で試したところ一応期待通りの動作はするようです。
しかし、手探りでやってもあまり意味が無いので、なんとかUNIX環境を導入するか学校で試したほうが良いです。
VirtualBoxの導入はどこで上手く行かなかったのでしょうか?

Re: ソケットプログラミングの基礎問題

Posted: 2013年6月16日(日) 17:30
by ツンドラ
実際にソースを試して頂きありがとうございます!
確かに無駄なデータを送るのは抑えたいです。

>>そのかわり、サーバー側で終端文字があったときにそこで変換を打ち切るという工夫は出来そうです。
アドバイスに従って可能ならば実装しようと思います。

virtualboxに関しましては、CentOSというのを導入してみたのですが、設定が終わってCentOSを再起動しようとすると、クリックや起動ボタンをしても反応しないという状況です。
今電話をしていまして、友人によれば「virtualboxの方がおかしいんじゃないか?」と言われたので、もう一度virtualboxをインストールしてみようと思いまいます。

CentOS以外にオススメのUNIX環境はありますでしょうか?

Re: ソケットプログラミングの基礎問題

Posted: 2013年6月16日(日) 17:38
by h2so5
CentOSよりもちょっと重いかもしれませんが、Ubuntuを試してみてはどうでしょう。
VirtualBox用のイメージがダウンロードできます。

http://www.ubuntulinux.jp/download/ja-remix-vhd

Re: ソケットプログラミングの基礎問題

Posted: 2013年6月16日(日) 17:44
by ツンドラ
URLありがとうございます!非常に助かります!

DL,導入後、このソースでできるかどうか実行してみます!

Re: ソケットプログラミングの基礎問題

Posted: 2013年6月16日(日) 19:43
by ツンドラ
h2so5 さんが書きました:CentOSよりもちょっと重いかもしれませんが、Ubuntuを試してみてはどうでしょう。
VirtualBox用のイメージがダウンロードできます。

http://www.ubuntulinux.jp/download/ja-remix-vhd
すみません。せっかく教えて頂いたのに私のPCでは重くて操作が非常に難しい状態でした。
明日、学校に行ったときに確認します!ありがとうございました!