○SDKにてTCP/IP通信

■WinSockを使うプログラムではWSock32.libをプロジェクトに参加させる必要がある

追加→既存項目の追加
にて

VCのディレクトリ\Lib\WSock32.lib

を追加

○もしくはマクロで、WSock32.libを参加させます。
#pragma comment(lib, "wsock32.lib")


(注意)
#include "winsock2.h"は、windows.hの上に書く必要がある。
下に書くとエラーが連発します。

//--------------------------------------------------------------------------------
/*
■TCP/IPクライアントクラス


#include <stdio.h>
#include <winsock2.h>

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

class TCPIP{
private:
	SOCKET s;
	WSADATA wsaData;
public :

bool TCPConnect(char *server,u_short port){

	if(WSAStartup(MAKEWORD(1, 1), &wsaData)!=0) return false;
	s = socket(PF_INET,SOCK_STREAM,0);
	if(s==INVALID_SOCKET) return false;
	LPHOSTENT ipHost = gethostbyname(server);
	if(ipHost == NULL) return false;
	SOCKADDR_IN sockadd;
	memset(&sockadd,0,sizeof(sockadd));
	sockadd.sin_family = AF_INET;
	sockadd.sin_port = htons(port);
	sockadd.sin_addr = *((LPIN_ADDR)*ipHost->h_addr_list);
	if(connect(s,(PSOCKADDR)&sockadd,sizeof(sockadd))!=0) return false;
	return true;
}
bool TCPSend(char*sendWord){
	int nRtn,i;
	//ポインタで渡された送信文字列はsizeofが使えないため
	//文字数をカウントします
	for(i=0;sendWord[i]!='\0';i++);
	nRtn = send(s,sendWord,i,0);//送信
	//nRtn==0				接続が終了しました
	//nRtn==SOCKET_ERROR	
	if(nRtn==SOCKET_ERROR || nRtn==0) return FALSE; else return TRUE;
}

int TCPRead(char*buff,int bfSize){
	int nRtn;
	nRtn = recv(s,buff,bfSize,0);//受信	
	//nRtn==0				接続が終了しました
	//nRtn==SOCKET_ERROR	エラー
	if(SOCKET_ERROR!=nRtn){
		buff[nRtn]='\0';
		return nRtn;//受信した文字数を返す
	}else{
		return 0;
	}
}

void TCPClose(){
	closesocket(s);
	WSACleanup();
}
};

int main(){
	TCPIP s;
	char buff[1024];
	buff[0]='\0';
	//接続
	if(s.TCPConnect("google.co.jp",80)) printf("接続OK\n"); else printf("接続ERR\n");
	//送信
	if(s.TCPSend("GET / HTTP/1.0\n\n")) printf("書き込みOK\n"); else printf("書き込みERR\n");
	//読み出し
	if(s.TCPRead(buff,(int)sizeof(buff))) printf("読み出しOK\n"); else printf("接続が終了したか切断されました\n");
	printf(buff);
	//閉じる 接続失敗の場合にも必要
	s.TCPClose();

	return 0;
}

//--------------------------------------------------------------------------------
上のクラスはrecvをブロッキングモードで使っているため、受信するまで待機します
ただし、何も受信しなかった場合recvでずっと待機してしまいプログラムがフリーズします
もしくは回線が遅い場合にウエイトをかませないとエラーが返り何も受信できません。
次はrecvをノンブロッキングモードに書き換えた物


#include <stdio.h>
#include <winsock2.h>

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

class TCPIP{
private:
	SOCKET s;
	WSADATA wsaData;
public :

bool TCPConnect(char *server,u_short port){

	if(WSAStartup(MAKEWORD(1, 1), &wsaData)!=0) return false;
	s = socket(PF_INET,SOCK_STREAM,0);
	if(s==INVALID_SOCKET) return false;
	LPHOSTENT ipHost = gethostbyname(server);
	if(ipHost == NULL) return false;
	SOCKADDR_IN sockadd;
	memset(&sockadd,0,sizeof(sockadd));
	sockadd.sin_family = AF_INET;
	sockadd.sin_port = htons(port);
	sockadd.sin_addr = *((LPIN_ADDR)*ipHost->h_addr_list);
	if(connect(s,(PSOCKADDR)&sockadd,sizeof(sockadd))!=0) return false;
	//recvをノンブロッキングモードにする
	unsigned long val=1;
	ioctlsocket(s, FIONBIO, &val);
	return true;
}
bool TCPSend(char*sendWord){
	int nRtn,i;
	//ポインタで渡された送信文字列はsizeofが使えないため
	//文字数をカウントします
	for(i=0;sendWord[i]!='\0';i++);
	nRtn = send(s,sendWord,i,0);//送信
	//nRtn==0				接続が終了しました
	//nRtn==SOCKET_ERROR	
	if(nRtn==SOCKET_ERROR || nRtn==0) return FALSE; else return TRUE;
}

int TCPRead(char*buff,int bfSize){
	int nRtn=1;
	char*pt=buff;
	//タイムアウトを約5秒にするためのループ
	while(nRtn && SOCKET_ERROR!=nRtn && 0<(bfSize-(buff-pt))){
		for(int i=0;i<50;i++){
			nRtn = recv(s,buff,bfSize-(buff-pt),0);//受信
			if(0<=nRtn) break;
			Sleep(100);
		}
		buff+=nRtn;
	}
	*buff='\0';
	//nRtn==0				接続が終了しました
	//nRtn==SOCKET_ERROR	エラー
	return (buff-pt);
}

void TCPClose(){
	closesocket(s);
	WSACleanup();
}
};




//--------------------------------------------------------------------------------

//■TCP/IPサーバー

#pragma comment(lib, "wsock32.lib")
#include <stdio.h>
#include <process.h>
#include <winsock2.h>

//マルチスレッドの切り分けスイッチ
#define MT
//リスンするポート番号
#define PORT 2000


unsigned __stdcall TcpReadToSend(void*so){
	SOCKET s=*((SOCKET*)so);

	while (1) {
		char buff[1024]="";
		//-------改行するまで受信を待つ--------
		char c=1;
		int i=0;
		while(c!='\n' && c!='\0'){
			int nRcv = recv(s,&c,1,0);
			if (nRcv == SOCKET_ERROR) goto error;//recvエラー
			if (nRcv == 0) goto error;//クライアントが切断
			buff[i++] = c;
		}
		buff[i] = '\0';
//		printf("%s",buff);//受信文字列
		//-------送信--------
		char *sendBuff="Hello Server";//送信文字列
		if(SOCKET_ERROR==send(s, sendBuff, (int)strlen(sendBuff), 0)){
			goto error;//sendエラー
		}
	}
error:
	if(SOCKET_ERROR==closesocket(s)){
		printf("%s\n","ソケットのクローズ失敗");
	}
	free(so);
#ifdef MT
	_endthreadex(0);
#endif
	return 0;
}


int main(){

	WSADATA wsaData;
	//winsockの初期化
	while(WSAStartup(WINSOCK_VERSION, &wsaData)) {//WinSockの初期化失敗
		WSACleanup();
		printf("%s\n","初期化失敗");
		Sleep(1000);
	}

	//ソケットを作成する
	SOCKET listen_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET==listen_s) {//ソケットのオープン失敗
		printf("%s\n","ソケットのオープン失敗");
		return 0;
	}
	SOCKADDR_IN saddr;
	//構造体を初期化する
	memset(&saddr, 0, sizeof(SOCKADDR_IN));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(PORT);
	saddr.sin_addr.s_addr = INADDR_ANY;

	int len=sizeof(struct sockaddr);
	//ソケットをアドレス、ポートに結びつける
	if (bind(listen_s, (struct sockaddr *)&saddr,len)) {//バインドエラー
		printf("%s\n","bindの失敗");
		return 0;
	}
	//ソケットを接続待ちの状態にする
	if (SOCKET_ERROR==listen(listen_s,SOMAXCONN)) {
		printf("%s\n","listenの失敗");
		return 0;
	}
	while(1){
		SOCKET*s;
		while(NULL==(s = (SOCKET*)malloc(sizeof(SOCKET))));
		//接続待ちのリクエストを一つ取り出し、接続を確立する

		*s= accept(listen_s,(struct sockaddr *)&saddr,&len);//接続されるまでここで待機
		printf("%s\n","accept");
		if (INVALID_SOCKET!=*s) {
#ifdef MT
			HANDLE th=(HANDLE)_beginthreadex(NULL,0,TcpReadToSend,(void*)s,0,NULL);//複数の送受信を受け付ける場合。スレッドを立てます

			if(th){
				//スレッドの優先度を下げる
				//SetThreadPriority( th , THREAD_PRIORITY_BELOW_NORMAL );
				while(!CloseHandle(th));//参照カウンタを一つ減らす
			}else{
				closesocket(*s);
				free(s);
			}
#else
			TcpReadToSend((void*)s);//一つのクライアントしか無い場合
#endif
		}else{

			free(s);
		}
	}

	//winsockの開放
	closesocket(listen_s);
	WSACleanup();

	return 0;
}


//--------------------------------------------------------------------------------

//■スレッドプール版 TCP/IPサーバー

#pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
#include <process.h>
#include <winsock2.h>
#include <ws2tcpip.h>

//スレッドプール
#define THREAD_POOL 10
//リスンするポート番号
#define PORT 1000


typedef struct _MYOVERLAPPED {
	DWORD  Internal; 
	DWORD  InternalHigh; 
	DWORD  Offset; 
	DWORD  OffsetHigh; 
	HANDLE hEvent;
	SOCKET s;
} MYOVERLAPPED,*LPMYOVERLAPPED;

HANDLE CompPort;


HANDLE     hIOMutex = CreateMutex (NULL, FALSE, NULL);

unsigned __stdcall thread(void*obj){
	LPMYOVERLAPPED myol=NULL;
	DWORD numberOfBytesTransferred=0;
	ULONG completionKey=0;
	
	while (1) { 
		BOOL ret = GetQueuedCompletionStatus(
			CompPort, 
			&numberOfBytesTransferred, 
			&completionKey, 
			(LPOVERLAPPED*)&myol, 
			INFINITE );
		
		
		if (ret) {
			char buff[1024]="";
			//-------改行するまで受信を待つ--------
			char c=1;
			int i=0;
			do{
				int nRcv = recv(myol->s,&c,1,0);
				if (nRcv == SOCKET_ERROR) goto error;//recvエラー
				if (nRcv == 0) goto error;//クライアントが切断
				if (c=='\0')goto error;
				buff[i++] = c;
			}while(c!='\n');
			buff[i] = '\0';
			printf("ThreadNo:%d buff:%s",(int)obj,buff);//受信文字列

			//重い処理のつもりのウエイト
			//Sleep(1000);
			
			//-------送信--------
			char *sendBuff="Hello Server";//送信文字列
			if(SOCKET_ERROR==send(myol->s, sendBuff, (int)strlen(sendBuff), 0)){
				goto error;//sendエラー
			}

		}
error:
		//時々ハンドルリークするためMutexを使う
		WaitForSingleObject(hIOMutex, INFINITE );
		//shutdown(myol->s,SD_BOTH);
		if(SOCKET_ERROR==closesocket(myol->s)){
			printf("%s\n","ソケットのクローズ失敗");
		}
		free(myol);
		ReleaseMutex(hIOMutex);
	}
	return 0;
}


int main(){
	CompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,THREAD_POOL);

	//スレッドを作成する
	for(int i=0;i<THREAD_POOL;i++){
		HANDLE hd=(HANDLE)_beginthreadex(NULL,0,thread,(void*)i,0,NULL);
		CloseHandle(hd);
	}

	WSADATA wsaData;
	//winsockの初期化
	while(WSAStartup(WINSOCK_VERSION, &wsaData)) {//WinSockの初期化失敗
		WSACleanup();
		printf("%s\n","初期化失敗");
		Sleep(1000);
	}

	//ソケットを作成する
	SOCKET listen_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET==listen_s) {//ソケットのオープン失敗
		printf("%s\n","ソケットのオープン失敗");
		return 0;
	}
	SOCKADDR_IN saddr;
	//構造体を初期化する
	memset(&saddr, 0, sizeof(SOCKADDR_IN));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(PORT);
	saddr.sin_addr.s_addr = INADDR_ANY;

	int len=sizeof(struct sockaddr);
	//ソケットをアドレス、ポートに結びつける
	if (bind(listen_s, (struct sockaddr *)&saddr,len)) {//バインドエラー
		printf("%s\n","bindの失敗");
		return 0;
	}
	//ソケットを接続待ちの状態にする
	if (SOCKET_ERROR==listen(listen_s,SOMAXCONN)) {
		printf("%s\n","listenの失敗");
		return 0;
	}

	while(1){
		LPMYOVERLAPPED st = NULL;
		//時々ハンドルリークするためMutexを使う
		WaitForSingleObject(hIOMutex, INFINITE );
		while(!(st=(LPMYOVERLAPPED) calloc (1, sizeof (MYOVERLAPPED))));
		st->s= accept(listen_s,(struct sockaddr *)&saddr,&len);//接続されるまでここで待機
		ReleaseMutex(hIOMutex);
		printf("%s\n","accept");
		if (INVALID_SOCKET!=st->s) {
			PostQueuedCompletionStatus ( CompPort, 0, 0,(LPOVERLAPPED)st);
		}else{
			free(st);
		}
	}
	//winsockの開放
	closesocket(listen_s);
	WSACleanup();

	return 0;
}


//--------------------------------------------------------------------------------


//■ノンブロッキング受信TCP/IPサーバー


#pragma comment(lib, "wsock32.lib")
#include <stdio.h>
//#include <process.h> //_beginthread
#include "winsock2.h"

SOCKET tcpServerStand(u_short uport){
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(1, 1), &wsaData)) {//WinSockの初期化失敗
		WSACleanup();
		return NULL;
	}
	SOCKET listen_s = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_s < 0) {//ソケットのオープン失敗
		WSACleanup();
		return NULL;
	}
	SOCKADDR_IN saddr;
	memset(&saddr, 0, sizeof(SOCKADDR_IN));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(uport);
	saddr.sin_addr.s_addr = INADDR_ANY;
	if (bind(listen_s, (struct sockaddr *)&saddr, sizeof(saddr)) == SOCKET_ERROR) {//バインドエラー
		closesocket(listen_s);
		WSACleanup();
		return NULL;
	}
	if (listen(listen_s, 0) == SOCKET_ERROR) {
		closesocket(listen_s);
		WSACleanup();
		return NULL; 
	}
	SOCKADDR_IN from;
	int fromlen = (int)sizeof(from);
	SOCKET s;
	 s= accept(listen_s, (SOCKADDR *)&from, &fromlen);//接続されるまでここで待機
	if (s == INVALID_SOCKET) {
		closesocket(listen_s);
		WSACleanup();
		return NULL;
	}

	closesocket(listen_s);//この接続待ちソケットはもう必要ない

	//ノンブロッキングに設定する
	unsigned long  i=1;
	ioctlsocket(s, FIONBIO, &i);

	return s;
}


void TcpReadToSend(SOCKET*so){
	SOCKET s=*so;
	if(s!=NULL){
		printf("接続\n");
		while (true) {
			char buff[1024]="";

			//-------ノンブロッキング受信--------
			int nRcv = recv(s, buff, sizeof(buff) - 1, 0);
			if (nRcv == 0){
				//エラーのため切断する
				break;
			}else if(nRcv>0){
				buff[nRcv] = '\0';
				printf("%s",buff);//受信文字列
			}


			//-------送信--------

			if(nRcv>0)	{
				int i=0;
				while(0>=i){
					//送信成功するまで繰り返す
					//ただし無限ループにならないようにする必要があり
					i=send(s,buff,nRcv,0);
				}
			}
			if(nRcv<0) Sleep(1);
		}
		closesocket(s);
		//WSACleanup();
		printf("切断\n");
	}
}

int main(){
	while(true){
		SOCKET s = tcpServerStand(2000);//接続されるまで待機します。
		TcpReadToSend(&s);//一つのクライアントしか無い場合
//		_beginthread((void(*)(void*))TcpReadToSend,0,&s);//複数の送受信を受け付ける場合。スレッドを立てます
	}
	return 0;
}


//--------------------------------------------------------------------------------

■TCPポートスキャン
一度接続してみて、接続できれば、true 接続できなければ false を返します。

	char *server="localhost";
	u_short port=2000;
	SOCKET s;
	WSADATA wsaData;
	if(WSAStartup(MAKEWORD(1, 1), &wsaData)!=0) return false;
	s = socket(PF_INET,SOCK_STREAM,0);
	if(s==INVALID_SOCKET) return false;
	LPHOSTENT ipHost = gethostbyname(server);
	if(ipHost == NULL) return false;
	SOCKADDR_IN sockadd;
	memset(&sockadd,0,sizeof(sockadd));
	sockadd.sin_family = AF_INET;
	sockadd.sin_port = htons(port);
	sockadd.sin_addr = *((LPIN_ADDR)*ipHost->h_addr_list);
	if(connect(s,(PSOCKADDR)&sockadd,sizeof(sockadd))!=0) return false;
	closesocket(s);
	WSACleanup();
	return true;




▲トップページ > Windows と C++