概要
自コンピュータのTCPサーバポート「12345」に接続し、送信と受信を各1回ずつ行うTCPクライアントプログラムのサンプルコードです。
サンプルコード
#include "stdafx.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment (lib, "ws2_32.lib")
#pragma comment (lib, "mswsock.lib")
#pragma comment (lib, "advapi32.lib")
#define DEFAULT_BUFLEN (4 * 1024)
#define DEFAULT_TARGET "localhost"
#define DEFAULT_PORT "12345"
int main()
{
int ret = 0;
// WINSOCKライブラリ初期化
WSADATA wsadata;
ret = WSAStartup(WINSOCK_VERSION, &wsadata);
if (ret != 0)
{
printf("WSAStartup failed with error: %d\n", ret);
return 1;
}
// ソケット情報
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// アドレス情報取得
struct addrinfo *result = NULL;
ret = getaddrinfo(DEFAULT_TARGET, DEFAULT_PORT, &hints, &result);
if (ret != 0)
{
printf("getaddrinfo failed with error: %d\n", ret);
WSACleanup();
return 1;
}
// 接続
SOCKET connectSocket = INVALID_SOCKET;
for (struct addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
{
// ソケット作成
connectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (connectSocket == INVALID_SOCKET)
{
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// 接続
ret = connect(connectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (ret == SOCKET_ERROR)
{
closesocket(connectSocket);
connectSocket = INVALID_SOCKET;
continue;
}
break;
}
// アドレス情報解放
freeaddrinfo(result);
result = NULL;
// 接続確認
if (connectSocket == INVALID_SOCKET)
{
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
// 送信
const char *sendbuf = "this is a test";
ret = send(connectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (ret == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(connectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", ret);
// 受信
char recvbuf[DEFAULT_BUFLEN];
ret = recv(connectSocket, recvbuf, sizeof(recvbuf), 0);
if (ret > 0)
{
printf("Bytes received: %d\n", ret);
}
else if (ret == 0)
{
printf("Connection closed\n");
closesocket(connectSocket);
WSACleanup();
return 1;
}
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(connectSocket);
WSACleanup();
return 1;
}
// 切断要求
ret = shutdown(connectSocket, SD_SEND);
if (ret == SOCKET_ERROR)
{
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(connectSocket);
WSACleanup();
return 1;
}
// 切断待ち
for (;;)
{
// 受信
ret = recv(connectSocket, recvbuf, sizeof(recvbuf), 0);
if (ret > 0)
{
printf("Bytes received: %d\n", ret);
}
else if (ret == 0)
{
printf("Connection closed\n");
break;
}
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
break;
}
}
// ソケット解放
closesocket(connectSocket);
// WINSOCKライブラリ解放
WSACleanup();
return 0;
}
各関数の解説
WSAStartup 関数
WinSockライブラリを初期化する。
プロセス開始時に1度だけ実行すること。
getaddrinfo 関数
サーバのアドレス情報を取得する。
第1引数には、接続先のIPアドレス、又はドメイン名を設定する。
第2引数には、接続先のポート番号を設定する。
第3引数には、取得するアドレス情報の基準を設定する。
第4引数には、取得したアドレス情報を格納する領域のポインタを設定する。ここにアドレス情報が格納される。
freeaddrinfo 関数
getaddrinfo 関数にて取得したアドレス情報を開放する。
不要になったアドレス情報は、必ず本関数で解放すること。
socket 関数
ソケットを作成する。
connect 関数
サーバへ接続する。
send 関数
サーバへ送信する。
recv 関数 (shutdown 関数実行前)
サーバから受信する。
shutdown 関数
サーバへ切断を通知する。
recv 関数 (shutdown 関数実行後)
切断を待つ。
closesocket 関数
ソケットを開放する。
不要になったソケットは、必ず本関数で解放すること。
WSACleanup 関数
WinSockライブラリを開放する。
プロセス終了時に1度だけ実行すること。