いろんなものはつながっている

ネットワークプログラミング基礎 マルチスレッド

sendやrecvを使って送信したり受信したりできるようになった。ただ、単にsendやrecvを使っただけではひとつのクライアントとのやりとりしかできない。複数のクライアントとやりとりするためにはなんらかの対応をしてやる必要がある。その方法のひとつがマルチスレッド化。あまりマルチスレッド化のメリットはないかもしれないが、エコーサーバのマルチスレッド化をしてみた。

クライアントがサーバに接続してきたらスレッドを作成し、作成したスレッドと接続したクライアントとやりとりするようにしてやった。
マルチスレッド1

エラー処理もなんにもしていなけどあらたに接続されるたびに_beginthreadexでスレッドを作成するようにした。

// マルチスレッドエコーサーバ

#include "stdafx.h"

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

#include <winsock2.h>
#include <ws2tcpip.h>
#include <process.h>

#define PORT 9876	// 使用するポート番号

#define BUFFER_SIZE 1024
#define MAX_CONNECTION 4

HANDLE ThreadArray[MAX_CONNECTION];

typedef struct ClientConnectInfo_ {
	int nSocket;
	struct sockaddr_in ClientAddr;
	int	nThreadIndex;
} CLIENT_CONNECT_INFO;


unsigned  __stdcall recvThread(void* pvClientConnectInfo)
{
	CLIENT_CONNECT_INFO ClientConnectInfo= *((CLIENT_CONNECT_INFO*)pvClientConnectInfo);

	// コネクションを受け付ける
	TCHAR szBuf[BUFFER_SIZE];
	TCHAR szResponse[BUFFER_SIZE];
	while(1){
		memset(szBuf, _T('\0'), BUFFER_SIZE);
		memset(szResponse, _T('\0'), BUFFER_SIZE);
		int nMsgSize = recv(ClientConnectInfo.nSocket, szBuf, sizeof(szBuf), 0);
		_tprintf(_T("%s %d\n"), szBuf, nMsgSize);
		if(_tcscmp(_T("quit"), szBuf) == 0) break;
		_stprintf(szResponse, _T("%s\n"), szBuf);
		_tprintf(_T("%s\n"), szResponse);
		nMsgSize = send(ClientConnectInfo.nSocket, szResponse, sizeof(szResponse), 0);
	}

	closesocket(ClientConnectInfo.nSocket);
	CloseHandle(ThreadArray[ClientConnectInfo.nThreadIndex]);
	ThreadArray[ClientConnectInfo.nThreadIndex] = 0;
  	_tprintf(_T("スレッド%d解放\n"), ClientConnectInfo.nThreadIndex);

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	// WinSockの初期化
	WSADATA data;
	WSAStartup(MAKEWORD(2,0), &data);

	// ソケットの生成(TCP用)
	int nSrcSocket = socket(AF_INET, SOCK_STREAM, 0);	

	// IP,ポート番号の設定
	struct sockaddr_in ServerAddr;
	memset(&ServerAddr, 0, sizeof(ServerAddr));
	ServerAddr.sin_port = htons(PORT);
	ServerAddr.sin_family = AF_INET;
	ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

	bind(nSrcSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr));

  	// コネクションの受付を開始
	listen(nSrcSocket, 1);
	memset(ThreadArray, 0, sizeof(ThreadArray));
	while(1){
		struct sockaddr_in ClientAddr;
		int nClientAddrSize = sizeof(ClientAddr);
		int nConnectedSocket = accept(nSrcSocket, (struct sockaddr*)&ClientAddr, &nClientAddrSize);
		_tprintf(_T("%s から接続を受けました\n"), inet_ntoa(ClientAddr.sin_addr));
		for(int i = 0; i < MAX_CONNECTION; i++){
			if(ThreadArray[i] == 0){
				CLIENT_CONNECT_INFO ClientConnectInfo;
				ClientConnectInfo.nSocket = nConnectedSocket;
				ClientConnectInfo.ClientAddr = ClientAddr;
				ClientConnectInfo.nThreadIndex = i;
				ThreadArray[i] = (HANDLE)_beginthreadex(NULL, 0, recvThread, &ClientConnectInfo, 0, NULL);
				_tprintf(_T("%d番目のスレッドスタート\n"), i);
				break;
			}
			if(i == (MAX_CONNECTION - 1)){
				_tprintf(_T("接続できません\n"));
			}
		}
	}

	closesocket(nSrcSocket);

	for(int i = 0; i < MAX_CONNECTION; i++){
		WaitForSingleObject(ThreadArray[i], INFINITE);
		CloseHandle(ThreadArray[i]); 
	}

	WSACleanup();

	return 0;

}
// クライアント側

#include "stdafx.h"

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

#include <winsock2.h>
#include <ws2tcpip.h>

#define PORT 9876	// 使用するポート番号

#define BUFFER_SIZE 1024

int _tmain(int argc, _TCHAR* argv[])
{
	// WinSockの初期化
	WSADATA data;
	WSAStartup(MAKEWORD(2,0), &data);

	// ソケットの生成(TCP用)
	int nClientSocket = socket(AF_INET, SOCK_STREAM, 0);	

	// IP,ポート番号の設定
	struct sockaddr_in ServerAddr;
	memset(&ServerAddr, 0, sizeof(ServerAddr));
	ServerAddr.sin_port = htons(PORT);
	ServerAddr.sin_family = AF_INET;
	ServerAddr.sin_addr.s_addr = inet_addr(_T("192.168.11.6"));

  	// コネクションを確立
	if(connect(nClientSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr))){
		_tprintf(_T("接続できませんでした\n"));
		return -1;
	}

	// メッセージの送信
 	printf("メッセージを入力してください\n");
	TCHAR szSendBuffer[BUFFER_SIZE];
	TCHAR szRecvBuffer[BUFFER_SIZE + 1];
	while (1){
		memset(szSendBuffer, _T('\0'), sizeof(szSendBuffer));
		memset(szRecvBuffer, _T('\0'), sizeof(szRecvBuffer));
		_tscanf(_T("%s"), szSendBuffer);
		//パケットの送信
		_tprintf(_T("入力:%s\n"), szSendBuffer);
		send(nClientSocket, szSendBuffer, sizeof(szSendBuffer), 0);
		if(_tcscmp(_T("quit"), szSendBuffer) == 0) break;
		//パケットの受信
		int nResvSize = recv(nClientSocket, szRecvBuffer, BUFFER_SIZE, 0);
		_tprintf(_T("受信した サイズ%d\n"), nResvSize);
		szRecvBuffer[nResvSize] = _T('\0');
		_tprintf(_T("%s"), szRecvBuffer);
	}
	
	closesocket(nClientSocket);
	WSACleanup();

	return 0;

}

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

スポンサード リンク

カテゴリー

スポンサード リンク