複数のクライアントからのデータを送る

アバター
shiro4ao
記事: 224
登録日時: 15年前
住所: 広島

複数のクライアントからのデータを送る

投稿記事 by shiro4ao » 13年前

クライアントからのデータを接続してる複数のクライアント達に流すテスト。
このままだと、切断されててもソケットがどんどん浪費されていく。
接続してるソケットと使ってないソケットを区別しないと・・・・

クラスにすればいいのかな?
でもそうすると、他のクライアント達が見えなくなる、送信できなくなる
クライアントの面倒を見るクラス達を他のクラスで面倒を見てやる???
だめだ。どうなっているのやら。

自分の設計が悪いのか、2度と使われることのないクラスばっかり増産してる気がする
再利用性と汎用性がおもいっきり矛盾してる。
正しいアプローチとか、定石ってないんだろうか。

CODE:

#include	
#include	
#include	
#include	
#pragma comment(lib, "ws2_32.lib") 

#define MAX_BUF 1024
#define MAX_SESSION 5		//クライアント用のWindowsだと多分ライセンス的にどうだったっけ

SOCKET SockTable[MAX_SESSION];	//実際に通信で使うソケットの配列
int gID;				//今何人いるか数えるカウンタ

//切断処理
void CloseConnection(int id){
	int ret;
	ret=1;
	char buf[1024];
	shutdown(SockTable[id], SD_SEND);
	while(ret==0)ret=recv(SockTable[id],buf,sizeof(buf),0);
	closesocket(SockTable[id]);
}

//実際にすべてのクライアントへデータを送る
int Send(SOCKET s[],char *buf,int size,int Flag){
	int i;
	for(i=0;i1)Send(SockTable,buf,MAX_BUF,0);
		if(ret<=0)break;
	}
	
	CloseConnection(id);
	ExitThread(TRUE);
}

//クライアントからの接続を受け付けて、クライアントのためのスレッドを開始
DWORD WINAPI AcceptThread(LPVOID lpvoid){
	int i;
	SOCKET  ServSock;
	struct  sockaddr_in addr;
	struct  sockaddr_in client;
	int	 len;
	int port=(int)lpvoid;

	// ソケットの作成
	ServSock= socket(AF_INET,SOCK_STREAM,0);

	// ソケットの設定
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.S_un.S_addr = INADDR_ANY;
	bind(ServSock, (struct sockaddr *)&addr, sizeof(addr));
	printf("接続待ちです\n");

	// TCPクライアントからの接続要求を待てる状態にする
	listen(ServSock, 1);

	// TCPクライアントからの接続要求を受け付ける
	len = sizeof(client);

	while(gID<MAX_SESSION){
		gID++;
printf("%d番目のクライアントがきました\n",gID);
		SockTable[gID]=accept(ServSock, (struct sockaddr *)&client, &len);
		CreateThread(NULL , 0 , MulticastThread ,(void*)gID, 0 ,NULL);	
	}
}

//クライアントからの受付を開始する関数
void StartAccept(int port){
	gID=0;
	CreateThread(NULL , 0 , AcceptThread ,(void*)port, 0 ,NULL);	
}


int main(void)
{ 	
	WSADATA wsaData;

	WSAStartup(MAKEWORD(2,0), &wsaData);
	StartAccept(5555);

	//スレッドごと巻き込んで終了するけど、正しい方法ってどうすればいいんだろう?
	getch();
	WSACleanup ();
	return 0;
}


最後に編集したユーザー shiro4ao on 2013年9月04日(水) 20:46 [ 編集 1 回目 ]

taketoshi
記事: 222
登録日時: 14年前

Re: 複数のクライアントからのデータを送る

投稿記事 by taketoshi » 13年前

私も昔IRCみたいなソフトをWinsockで書きました。

そのときは構造体で接続ソケットを管理して、
WinMain関数(間違え、プロシージャでした)のWPARAMに通知をしてきたソケット情報が入っているので
それと照合して、WPARAM以外のソケットに一斉送信するような仕組みにしました。

こんな感じです。死ぬほどへたくそなコードですが参考になれば

CODE:

////////////////////////////////////////////////////////////////////////
//ソケットとクライアント情報を管理する構造体
//
////////////////////////////////////////////////////////////////////////
typedef struct{
	int nId;			//構造体の要素数+1
	SOCKADDR_IN from;	//クライアント情報
	SOCKET s;			//ソケット
}DATA;

////////////////////////////////////////////////////////////////////////
//受信関数
//戻り値:int
////////////////////////////////////////////////////////////////////////
int server::read(WPARAM wParam){
	char szBuffer[256];
		for(i = 0;i < MAX_MEMBER;++i){
			if((SOCKET)wParam == MemData[i].s){
				wsprintf(szOutBuff,"%s",inet_ntoa(MemData[i].from.sin_addr));
			}
		}
		for(i = 0;i < MAX_MEMBER;++i){
			if((SOCKET)wParam == MemData[i].s){	//受信ソケットの照合作業ですこの作業をやらないと何故か接続オーバーしたクライアントからゴミを送りつけられる。必ずソケットは選択受信すること。
				memset(szBuffer,0,sizeof(szBuffer));
				nRet =recv(MemData[i].s,szBuffer,sizeof(szBuffer),0);
				szBuffer[nRet] = '\0';
				wsprintf(szInfoBuff,"%s:%s\r\n",szOutBuff,szBuffer);
				SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
				for(i = 0;i < MAX_MEMBER;++i){//サーバーにきたクライアントの文章を他のクライアントに転送
					if((SOCKET)wParam != MemData[i].s)
						send(MemData[i].s,szInfoBuff,(int)strlen(szInfoBuff),0);
				}
			}
		}
		return 0;
}
最後に編集したユーザー taketoshi on 2012年1月29日(日) 15:19 [ 編集 1 回目 ]

アバター
shiro4ao
記事: 224
登録日時: 15年前
住所: 広島

Re: 複数のクライアントからのデータを送る

投稿記事 by shiro4ao » 13年前

なるほど、クライアントに纏わる変数を構造体でまとめるのですね。
バラバラな配列を操作するよりわかりやすいです。