学校の課題で困っています。

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

学校の課題で困っています。

#1

投稿記事 by yamasan » 15年前

初めまして。c++を学んでいます(苦手です)。大学で課題が出たのですが、先週から風邪を引いてしまい授業を欠席してしまったため、課題が終わりません。
エコーサーバを作るという課題で、配布された資料や本、友人に聞いたりして、途中までは頑張ったのですが、その後がわかりません。
プログラムは次の通りです。

EchoSever.cpp

コード:

                                                                                                  
#include <iostream>
#include <string>

#include <WinSock.h> 
#include "CommSocket.h"

static void DgramEchoServer(int port);

int main()
{
	int port = 10000;

	WSADATA wsaData;
	WSAStartup(2, &wsaData);

	DgramEchoServer(port);

	WSACleanup();

	return 0;

}

static void DgramEchoSever(int port)
{
	UDPSocket udpSock;

	udpSock.Bind(port);

	for (int i=0; i < 4; i++){

		string msg;
		udpSock >> msg;

		cout << msg << endl;

		udpSock << msg;

	}

}

コード:

EchoClient.cpp
#include<iostream>
#include<string>

#include <WinSock.h>
#include "CommSocket.h"

static void DgramEchoClient(string addr, int port);

int main()
{
	string addr("127.0.0.1");
	int port = 10000;

	WSADATA wsaData;
	WSAStartup(2, &wsaData);

	DgramEchoClient(addr, port);

	WSACleanup();

	return 0;
}

static void DgramEchoClient(string addr, int port)
{
	UDPSocket udpSock;

	udpSock.SetPeerAddress(addr, port);

	for (int i = 0; i < 4; i++){

		cin >> udpSock;

		cout << udpSock << endl;
	}
}

コード:

CommSocket.h
using namespace std;

const int BUFF_SIZE = 1024;

class CommSocket
{
protected:
	int m_nSock;

	char m_pcRecvBuffer[BUFF_SIZE];

public:
	CommSocket();
	virtual ~CommSocket() {};

	virtual int SendString(string msg) = 0;

	virtual int RecvString(string &msg) =0;

	friend istream &operator>>(istream &stream, CommSocket &commSock);
	friend ostream &operator<<(ostream &stream, CommSocket &commSock);

	friend CommSocket &operator>>(CommSocket &commSock, string &msg);
	friend CommSocket &operator<<(CommSocket &commSock, string &msg);

};

class UDPSocket
	: public CommSocket
{
private:

	sockaddr_in m_saPeerAddr;

public:
	UDPSocket();
	~UDPSocket();
	


	void Bind(int port);

	void SetPeerAddress(string addr, int port);

	int SendString(string msg);

	int RecvString(string &msg);
	
};

class TCPSocket
	: public CommSocket
{
public:
	int SendString(string msg);
	int RecvString(string &msg);

};
穴埋めになっており、ここまでは何とか配布された資料を見て、埋めることができました。そして最後に次のファイルがあり
CommSocket.cpp

コード:

#include <iostream>
#include <string>

#include <WinSock.h>
#include "CommSocket.h"

CommSocket::CommSocket(void)
	:   m_nSock(-1)
{
	memset( m_pcRecvBuffer, 0, sizeof( m_pcRecvBuffer) );
//受信バッファを初期化する
}

istream &operator >> (istream &stream, CommSocket& commSock)
{
	
   //stream から取得した文字列を通信相手に送る

	return stream;
}

ostream &operator <<(ostream &stream, CommSocket& commSock)
{
	//通信相手から受信した文字列をstreamへ出力する

	return stream;
}


CommSocket &operator >>(CommSocket &commSock, string &msg)
{
	string &msg = recvfrom(, , BUFF_SIZE, 0,
		reinterpret_cast<struct sockaddr*>(   ),      );//通信相手から文字列を受信する

	return commSock;
}

CommSocket &operator <<(CommSocket &commSock, string &msg)
{
	string &msg = sendto(, , BUFF_SIZE, 0,
		reinterpret_cast<struct sockaddr*>(&   ), sizeof(    ) );// 通信相手へ文字列を送信する

	return commSock;
}

UDPSocket::UDPSocket()
	:   CommSocket()
{
 m_nSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);          // メッセージの送受信に使うソケットを作成する

}

UDPSocket::UDPSocket()
{
	closesocket(m_nSock);//ソケットを閉じる
}

void UDPSocket::Bind(int port)
{
	memset(&    , 0, sizeof(     ));
	servAddr.sin_family = AF_INET;
	servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servAddr.sin_port = htons(servPort);  //ローカル用アドレス構造体へ必要な値を格納する

	bind(m_nSock, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr) //ソケットとローカル用アドレス構造体を結びつける
}

void UDPSocket::SetPeerAddress(string addr, int port)
{
	//通信相手用アドレス構造体へ必要な値を格納する
}

int UDPSocket::SendString(string msg)
{
	//文字列を送信する

	int res = 0;       // sendto()の戻り値を代入する

	return res;
}

int UDPSocket::RecvString(string &msg)
{
	//文字列を受信する

	int res = 0;      //recvfrom() の戻り値を代入する

	return res;
}
このcommsocket.cppを完成させたいのですが、資料を見ても参考にするものがないため解くことができません。
提出期限が迫っており、本当の課題はこれを完成させた後、追加機能を検討することなのですが、まずはこの4つを完成させなければ先へ進めません。
足りないのはコメントの部分なのです.
空白が多く、甘えた質問かもしれませんが、よければご教示ください。お願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 学校の課題で困っています。

#2

投稿記事 by softya(ソフト屋) » 15年前

winsockについて、何処まで理解されていますか?

例えば、下記のページとかは理解できますでしょうか?
http://www.geekpage.jp/programming/winsock/

【追記】
あとコンパイルが通りません。コンパイルされましたか?
何処まで変更しても良いかも分からないので、ソースに手を付けられませんので元の穴埋めしていない状態のソースコードも示してください。

【追記の追記】
迫っている期限の正確な日時も教えてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

yamasan

Re: 学校の課題で困っています。

#3

投稿記事 by yamasan » 15年前

わかりにくくてすみません。元のソースコードはこれです。
CommSocket.cpp

コード:

#include <iostream>
#include <string>

#include <WinSock.h>
#include "CommSocket.h"

CommSocket::CommSocket(void)
	:   m_nSock(-1)
{
               //受信バッファを初期化する
}

istream &operator >> (istream &stream, CommSocket& commSock)
{
	
   //stream から取得した文字列を通信相手に送る

	return stream;
}

ostream &operator <<(ostream &stream, CommSocket& commSock)
{
	//通信相手から受信した文字列をstreamへ出力する

	return stream;
}


CommSocket &operator >>(CommSocket &commSock, string &msg)
{
	//通信相手から文字列を受信する

	return commSock;
}

CommSocket &operator <<(CommSocket &commSock, string &msg)
{
	// 通信相手へ文字列を送信する

	return commSock;
}

UDPSocket::UDPSocket()
	:   CommSocket()
{
          // メッセージの送受信に使うソケットを作成する

}

UDPSocket::UDPSocket()
{
	//ソケットを閉じる
}

void UDPSocket::Bind(int port)
{  

         //ローカル用アドレス構造体へ必要な値を格納する

        //ソケットとローカル用アドレス構造体を結びつける
}

void UDPSocket::SetPeerAddress(string addr, int port)
{
	//通信相手用アドレス構造体へ必要な値を格納する
}

int UDPSocket::SendString(string msg)
{
	//文字列を送信する

	int res = 0;       // sendto()の戻り値を代入する

	return res;
}

int UDPSocket::RecvString(string &msg)
{
	//文字列を受信する

	int res = 0;      //recvfrom() の戻り値を代入する

	return res;
}

これが元のソースコードです。空欄を完全に埋めていないのでまだコンパイルはしてません。「ほかのコードでも必要な場合は変更してもよい。」とはあったので変更はできます。
winsockについては現在、勉強を始めたばかりなので、サンプルのソースコードを見て、UDPサーバ、クライアントをまねて作ることくらいしかできません。
これからも課題があるので春休み期間中に勉強したいと思っているのですが、期限が2月1日までなので困っています。
関係ないことなのですが、他の教科テストも同じ1日にあるので時間がなくてあせっています。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 学校の課題で困っています。

#4

投稿記事 by softya(ソフト屋) » 15年前

Cで書けるなら、まずそちらを書いてみてください。
C++化のサポートをします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

yamasan

Re: 学校の課題で困っています。

#5

投稿記事 by yamasan » 15年前

何度もすみません。正直、cでも書ける自信がありません。
CommSocket.cppの自分で解いた部分のご教示お願いします。

1. //受信バッファを初期化するの部分は memset( m_pcRecvBuffer, 0, sizeof( m_pcRecvBuffer) ); であってますか。
2. //streamから取得した文字列を通信相手へ送るの書き方の例を教えてくれませんか。
3. //通信相手から文字列を受信するの部分は の形でよいでしょうか。
   その場合 msg = recv( m_nSock,   , BUFF_SIZE, 0,); になると思ったのですが、m_nSockと2つ目が何が入るのかわかりません。
4.//ローカル用アドレス構造体へ必要な値を格納する の部分でrecv(int socket, void *buf, size_t len, int flags);  のような書き方の例を教えてくれませんか。
5. 4の次の//ソケットとローカル用アドレス構造体を結びつけるは bind(m_nSock, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr) でいいでしょうか。

質問が多くてすみません。よろしくお願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 学校の課題で困っています。

#6

投稿記事 by softya(ソフト屋) » 15年前

すいません、明日まとめて回答させていただきます。
申し訳ないです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

yamasan

Re: 学校の課題で困っています。

#7

投稿記事 by yamasan » 15年前

お手数おかけします。よろしくおねがいします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 学校の課題で困っています。

#8

投稿記事 by softya(ソフト屋) » 15年前

すいません。遅くなりました。

>1. //受信バッファを初期化するの部分は memset( m_pcRecvBuffer, 0, sizeof( m_pcRecvBuffer) ); であってますか。

char m_pcRecvBuffer[BUFF_SIZE];と実体宣言なので一応大丈夫です。

>2. //streamから取得した文字列を通信相手へ送るの書き方の例を教えてくれませんか。

friend関数で更にistreamのオーバーライドなんて結構高度なことをしてますね。
ここの使い方の資料とか説明は無かったのでしょうか?
とりあえず、これで良いと思うのですが。

コード:

    string msg;
    stream >> msg;		//取得
    commSock << msg;	//送信

    return stream;

>3. //通信相手から文字列を受信するの部分は の形でよいでしょうか。
   その場合 msg = recv( m_nSock,   , BUFF_SIZE, 0,); になると思ったのですが、m_nSockと2つ目が何が入るのかわかりません。

m_nSockでOKですよ。
バッファは1.でクリアしたm_pcRecvBufferです。

>4.//ローカル用アドレス構造体へ必要な値を格納する の部分でrecv(int socket, void *buf, size_t len, int flags);  のような書き方の例を教えてくれませんか。

bindの所ですよね。

コード:

	struct sockaddr_in servAddr;
	
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.S_un.S_addr = INADDR_ANY;
    servAddr.sin_port = htons(port);  //ローカル用アドレス構造体へ必要な値を格納する
だと思います。引数にポート番号があるので使わないといけません。

>5. 4の次の//ソケットとローカル用アドレス構造体を結びつけるは bind(m_nSock, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr) でいいでしょうか。
OKです。

[追記]
とりあえずコンパイルは通るようにしてください。
そうしないと動作確認できませんので、少しづつ組み上げるにも問題があります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 学校の課題で困っています。

#9

投稿記事 by softya(ソフト屋) » 15年前

全体を見なおして、元のコードに問題を見つけたので書いておきます。

コード:

UDPSocket::UDPSocket()
{
    //ソケットを閉じる
}
//どうみてもデストラクタなのですが、名前がコンストラクタです。エラーになるので
UDPSocket::~UDPSocket()
{
	//ソケットを閉じる
}
//が正しいです。
あと、yamasanさんの書いたコードで

コード:

CommSocket &operator >>(CommSocket &commSock, string &msg)
{
    string &msg = recvfrom(, , BUFF_SIZE, 0,
        reinterpret_cast<struct sockaddr*>(   ),      );//通信相手から文字列を受信する
 
    return commSock;
}
 
CommSocket &operator <<(CommSocket &commSock, string &msg)
{
    string &msg = sendto(, , BUFF_SIZE, 0,
        reinterpret_cast<struct sockaddr*>(&   ), sizeof(    ) );// 通信相手へ文字列を送信する
 
    return commSock;
}
はCommSocketクラスではなく継承したクラス側のUDPSocketで書くべきだと思います。
なので、ここで書くべきことはcommSock.RecvStringやcommSock.SendStringを呼び出す事でしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

yamasan

Re: 学校の課題で困っています。

#10

投稿記事 by yamasan » 15年前

詳しく説明していただいてありがとうございます。
早速やってみます。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 学校の課題で困っています。

#11

投稿記事 by softya(ソフト屋) » 15年前

すいません。bindの所ですが、m_saPeerAddrが用意されていたので

コード:

    struct sockaddr_in servAddr;
    
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.S_un.S_addr = INADDR_ANY;
    servAddr.sin_port = htons(port);  //ローカル用アドレス構造体へ必要な値を格納する

コード:

	//	ローカル用アドレス構造体へ必要な値を格納する
	m_saPeerAddr.sin_family = AF_INET;
	m_saPeerAddr.sin_addr.S_un.S_addr = INADDR_ANY;
	m_saPeerAddr.sin_port = htons(port);
に訂正させてもらいます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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