○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++