質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

windows環境でのTCP通信プログラムについて

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 762

score 8

前提・実現したいこと

C++、WindowsでのTCP通信プログラムをスレッドを使用して作成

発生している問題・エラーメッセージ

スレッドを作成してTCPサーバ機能を作成、accept関数で待ちが発生せず一瞬で通りぬける。
結果、recvでエラーコード10038の接続エラーが発生。

該当のソースコード

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
    LPSTR lpsCmdLine, int nCmdShow)
{
    MSG msg;
    BOOL bRet;
    if (!InitApp(hCurInst))
        return FALSE;
    if (!InitInstance(hCurInst, nCmdShow))
        return FALSE;
    // メッセージを取得
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (bRet == -1) {
            break;
        }
        else {
            TranslateMessage(&msg);    // メッセージを変換
            DispatchMessage(&msg);     // メッセージを送出
        }
    }
    return (int)msg.wParam;
}
~~~~~~~空のウィンドウにプロシージャ登録してます~~~~~~~~~~~~
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    PAINTSTRUCT ps;
    HDC hdc;
    LPCTSTR lpszStr = TEXT("test");
    static MYDATA data;
    static HANDLE hTh;
    static DWORD dwID;
    static MYDATA data2;
    static HANDLE hTh2;
    static DWORD dwID2;
    int id;

    switch (msg) {
    case WM_CREATE:
        data.hWnd = hWnd;
        data.bEnd = false;
        hTh = CreateThread(NULL, 0, ServerThread,
        (LPVOID)&data, 0, &dwID);
        }
    ~~~~~~~省略~~~~~~~~~~~
    return 0;
}
DWORD WINAPI ServerThread(LPVOID lpdata)
{
    MYDATA *lpmydata = NULL;
    lpmydata = (MYDATA*)lpdata;
    TcpClass tcpClass;
    char recvBuff[256];
    int recvlen = 0;

    AllocConsole();
    FILE* fp;
    freopen_s(&fp, "CONOUT$", "w", stdout);
    freopen_s(&fp, "CONIN$", "r", stdin);

    //TCP通信準備
    tcpClass.Init();
    tcpClass.BindListenAccept();

    while (lpmydata->bEnd == false) {
        cout << "通信中...\n";

        recvlen = tcpClass.Recv(recvBuff, 256);
        if (recvlen > 0) {
            cout << "受信: " << recvBuff;
        }

        Sleep(5000);
    }
    FreeConsole();

    return 0;
}
#include "TcpClass.h"

class TcpClass
{
    SOCKET sock;
public:
    TcpClass();
    ~TcpClass();

    int Init();
    int BindListenAccept();
    int Recv(char *buf, int size);
    int Send(char *buf, int size);
    int CloseSocket();
    int Connect();
};
int TcpClass::Init()
{
    WSADATA wsadata;
    int ret = 0;

    // WSAStartup
    if (WSAStartup(MAKEWORD(2, 2), &wsadata)) {
        cout << "WSAStartup failed\n";
        WSACleanup();
        return RET_ERROR;
    }

    // ソケット生成
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        cout << "socket failed\n";
        return RET_ERROR;
    }
}

int TcpClass::BindListenAccept()
{
    int ret = 0;
    int accept_len = 0;
    struct sockaddr_in accept_addr;
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.S_un.S_addr = INADDR_ANY;
    addr.sin_port = htons(12345);

    do {
        //bind
        ret = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
        if (ret != 0) {
            cout << "bind failed\n";
            break;
        }

        //listen
        ret = listen(sock, 5);
        if (ret != 0) {
            cout << "bind failed\n";
            break;
        }

        //accept
        sock = accept(sock, (struct sockaddr *)&accept_addr, &accept_len);
        if (sock < 0) {
            cout << "accept failed\n";
            break;
        }
    } while (0);

    if (ret != 0) {
        return RET_ERROR;
    }

    return RET_NORMAL;
}

int TcpClass::Recv(char *buf, int size)
{
    int ret = 0;
    ret = recv(sock, buf, size, 0);
    if (ret < 0) {
        cout << "recv failed :" << WSAGetLastError() << "\n";
    }
    return ret;
}
int TcpClass::Send(char *buf, int size)
{
    int ret = 0;
    ret = send(sock, buf, size, 0);
    if (ret < 0) {
        cout << "send failed\n";
    }
    return ret;
}
int TcpClass::Connect()
{
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    InetPton(addr.sin_family, _T("127.0.0.1"), &addr.sin_addr.S_un.S_addr);


    int ret = 0;

    ret = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
    if (ret != 0) {
        cout << "connect failed\n";
    }

    return ret;
}

試したこと

デバッガで確認したところacceptで待ちが発生することなく通り抜けてしまっています。recv関数のエラーコードは10038です。
コンソールアプリケーションで同じ方法でサーバを作成したものを使用するとacceptで待ちが発生し通信も成功します。

補足情報(FW/ツールのバージョンなど)

visualstudio2015commyunity

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

acceptの扱いがいくつか気になります。

https://linuxjm.osdn.jp/html/LDP_man-pages/man2/accept.2.html

addrlen 引き数は入出力両用の引き数である。呼び出し時には、呼び出し元が addr が指す構造体のサイズ (バイト単位) で初期化しておかなければならない。 返ってくる時には、接続相手のアドレスの実際の大きさが格納される。

となっているので、accept_len = sizeof(accept_addr);を行う必要があるように思います。

また、返り値がretに格納されないためacceptの異常終了を検知できていません。

最後に、sockを使いまわしているのが若干気になります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/23 19:03

    仰る通りaddrlenの取り扱いを間違えておりました。
    修正後、正常に動きました。ありがとうございます。

    キャンセル

0

そのエラーコードを見ると、

意味 : 非ソケットに対してソケット操作を試みました。

とのことですんで、おそらくソケットの作成/Openを失敗してるものと思われます

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る