プログラミングメモ →目次


スレッドでのTCPソケット送受信(VC++)

Windows Sockets APIを使用するTCPソケット送受信のメモです。受信処理は、スレッドの中で行い、マルチスレッドで、通信できるようになります。

tcp_server()は、サーバー側のプログラムです。listen用のソケットを作成して、listenをする、クライアントからの接続要求を受けたら、新しいスレッドを起こして、またlistenを繰り返します。
クライアントをAcceptして、通信用のソケットを作成して、受信、送信を繰り返します。

クライアント側のプログラムは、TCPソケット送受信を参照します。

#include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

DWORD WINAPI tcp_comm_thread(LPVOID lpParam);

class CTcpCommThread
{
public:
    HANDLE hThread;
    DWORD ThreadId;
    SOCKET sockListen;

    CTcpCommThread()
    {
        hThread = NULL;
    }

    void Start()
    {
        hThread = CreateThread(NULL, 0, tcp_comm_thread, (void *)this, 0, &ThreadId);
    }

    ~CTcpCommThread()
    {
        if (hThread)
        {
            if (WAIT_TIMEOUT == WaitForSingleObject(hThread, 1000 ))
            {
                TerminateThread(hThread, 0);
            }

            CloseHandle(hThread);
            hThread = NULL;
            printf("CloseHandle().\r\n");
        }
    }
};

void Release(CTcpCommThread* lpParam)
{
    // 省略↓
    // newで作成されたCTcpCommThreadのオブジェクトをdeleteする処理
}

DWORD WINAPI tcp_comm_thread(LPVOID lpParam)
{
    SOCKET sockListen = ((CTcpCommThread*)lpParam)->sockListen;
    SOCKET sockWork;

    struct sockaddr_in sockAddrInWork;
    int iSizeofSockAddrInWork = sizeof(sockAddrInWork);
    sockWork = accept(sockListen, 
                      (struct sockaddr *)&sockAddrInWork, 
                      &iSizeofSockAddrInWork);
    if (INVALID_SOCKET == sockWork)
    {
        closesocket(sockListen);
        return -1;
    }

    while(1) 
    {
        char buff[256];
        memset(buff, 0, sizeof(buff));
        int len = recv(sockWork, buff, 256, 0); 
        if(len <= 0) 
            break;
        printf("Data Received = %s\n", buff);

        strcat(buff, "3.");
        send(sockWork, buff, strlen(buff)+1, 0);

    }
    closesocket(sockWork);
    printf("Eof thread.\n");
    Release((CTcpCommThread*)lpParam);
    ExitThread(0);
    return 0;
}


void tcp_server()
{
    unsigned short port = 10000;
    SOCKET sockListen;
    struct sockaddr_in sockAddrInListen;

    memset(&sockAddrInListen, 0, sizeof(sockAddrInListen));
    sockAddrInListen.sin_port = htons(port);
    sockAddrInListen.sin_family = AF_INET;
    sockAddrInListen.sin_addr.s_addr = htonl(INADDR_ANY);

    sockListen = socket(AF_INET, SOCK_STREAM, 0);
    if (INVALID_SOCKET == sockListen)
        return;

    if (SOCKET_ERROR == bind(sockListen, 
                             (struct sockaddr *) &sockAddrInListen, 
                             sizeof(sockAddrInListen)))
    {
        closesocket(sockListen);
        return;
    }

    for (int n = 0; n < 100; n ++)
    {
        if (SOCKET_ERROR == listen(sockListen, SOMAXCONN))
        {
            closesocket(sockListen);
            return;
        }

        fd_set mask;
        FD_ZERO(&mask);
        FD_SET(sockListen, &mask);
        struct timeval tv={ 1, 0 };

        int ret = select((int)sockListen+1, &mask, NULL, NULL, &tv);
        if (ret == SOCKET_ERROR)
        {
            break;
        }
        else if (ret == 0)
        {
            printf("wait 1 second ...\r\n");
            continue;
        }
        else if (FD_ISSET(sockListen, &mask))
        {
            CTcpCommThread* ptcthread = new CTcpCommThread();
            ptcthread->sockListen = sockListen;
            ptcthread->Start();    
        }
    }
    closesocket(sockListen);
}


int main(int argc, char* argv[])
{
    WSADATA wsadata;
    if (0 != WSAStartup(MAKEWORD(2,0), &wsadata))
    {
        printf("WSAStartup Faild.\n");
        return -1;
    }
    tcp_server();
    WSACleanup();
    return 0;
}