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

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

ただいまの
回答率

90.75%

  • Visual Studio

    1699questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • Windows

    1365questions

    Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

  • OpenCV

    970questions

    OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

  • TCP

    154questions

    TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

  • UDP

    55questions

    UDP(User Datagram Protocol)とは、トランスポート層のプロトコルであり、コネクション型のデータサービスです。IPネットワーク上の別のホストにコンピュータのアプリケーションがメッセージを送ることができ、転送チャンネルやデータ経路を設定する必要はありません。TCPに比べて高速であるが、信頼性が薄いという特徴があります。

VS2015C++でwinsock,OpencvによるTCP画像送信プログラム

解決済

回答 1

投稿

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

MOTOZOMBIE

score 1

前提・実現したいこと

私はネットワーク初心者です.環境は,VS2015C++でwinsockとOpencvを使ってプログラミングしています
実現したいことは,
・TCPのサーバでMat型の画像を読み込む.

・Mat型の画像をエンコードする

・サーバに接続したクライアントにエンコード画像を送る.

・クライアント側で,デコードする.

・画像を出力する
ということをしたいと考えています.
 !!!                    まだ実装段階でないのでスパゲティとなっております.                     !!!

やっていて,すごく楽しい内容なので,これで躓きたくありません.
ですので,ぜひともご回答お願い致します!

発生している問題

・クライアント側で,文字が最初の3文字しか受け取れない
・バッファのサイズを大きくすると,オーバーフローとなってしまう.
・サーバ側の,  len = sizeof(client);  の意味がわからない.

・スパゲティコード

該当のソースコード

//サーバ側
#include <iostream>
#include <winsock2.h>
#include <opencv2/opencv.hpp>
#include <vector>
#pragma comment(lib, "ws2_32.lib")

#define BUFFER_SIZE 999999

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    /*                        宣言                        */
    WSADATA wsaData;
    SOCKET sock0;
    SOCKET sock;

    struct sockaddr_in addr;    //自身のソケットの設定
    struct sockaddr_in client;    //相手のソケットの設定
    int len;

    Mat src = imread(argv[1]);

    char buf[BUFFER_SIZE];
    vector<unsigned char> enc_buf;

    int size = src.rows * src.cols;

    /*                        初期化                            */
    // winsock2の初期化
    WSAStartup(MAKEWORD(2, 0), &wsaData);

    // ソケットの作成
    sock0 = socket(AF_INET, SOCK_STREAM, 0);
    // ソケットの設定
    //アドレスファミリ
    addr.sin_family = AF_INET;
    //ポート番号
    addr.sin_port = htons(12345);
    //IPアドレス INADDR_ANY : どのアドレスからの接続でも受け入れる
    addr.sin_addr.S_un.S_addr = INADDR_ANY;

    //sock0にソケットの設定を埋め込む
    bind(sock0, (struct sockaddr *)&addr, sizeof(addr));

    //エンコードの設定
    vector<int> param = vector<int>(2);
    //jpg : CV_IMWRITE_JPEG_QUALITY
    //png : CV_IMWRITE_PNG_COMPRESSION
    param[0] = CV_IMWRITE_JPEG_QUALITY;
    //エンコードの画質 : 0 ~ 100
    param[1] = 85;

    // キューの作成
    //listen(待つソケット,接続の最大キュー)
    listen(sock0, 3);

    /*                        メイン処理                            */
    //入力画像をエンコード
    imencode(".jpg", src, enc_buf, param);
    Mat jpgimage = imdecode(enc_buf, CV_LOAD_IMAGE_COLOR);

    //エンコード内容を300字表示
    for (int i = 0; i < 300; i++) cout << enc_buf[i];
    cout << endl;

    //srcが連続的なバイト列だったら、要素サイズ * 画像サイズを。違えば0を返す
    cout << "Original Data Size: " << (src.isContinuous() ? (src.elemSize() * size) : 0) << " [byte]" << endl;
    cout << "Encoded Image Size: " << enc_buf.size() << " [byte] (quality=" << param[1] << ")" << endl << endl;
    while (true) {
        len = sizeof(client);
        //ソケット接続待機
        //accept(受け取るソケット,クライアント情報,"不明")
        sock = accept(sock0, (struct sockaddr *)&client, &len);

        //相手のIP, portを表示
        cout << "Cliant : IP = " << inet_ntoa(client.sin_addr) << endl;
        cout << "Cliant : port = " << ntohs(client.sin_port) << endl << endl;

        for (int i = 0; i < enc_buf.size(); i++) buf[i] = enc_buf[i];
        int check = sendto(sock, buf, enc_buf.size(), 0, (struct sockaddr *)&    addr, sizeof(addr));
    }
    //セッションの終了
    closesocket(sock);
    // winsock2の終了処理
    WSACleanup();

    return 0;
}
//クライアント側
#include <iostream>
#include <winsock2.h>
#include <opencv2/opencv.hpp>
#include <vector>
#pragma comment(lib, "ws2_32.lib")

#define BUFFER_SIZE 999999

using namespace std;
using namespace cv;

int main()
{
    WSADATA wsaData;
    struct sockaddr_in server;
    SOCKET sock;

    char buf[BUFFER_SIZE];
    vector<unsigned char> enc_buf;


    // winsock2の初期化
    WSAStartup(MAKEWORD(2, 0), &wsaData);

    // ソケットの作成
    sock = socket(AF_INET, SOCK_STREAM, 0);

    // 接続先指定用構造体の準備
    server.sin_family = AF_INET;
    server.sin_port = htons(12345);
    server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    // サーバに接続
    connect(sock, (struct sockaddr *)&server, sizeof(server));


    //memset(メモリブロック(配列), どこの値から, どこまでか)
    memset(buf, 0, BUFFER_SIZE);

    //画像データ受信
    recvfrom(sock, buf, BUFFER_SIZE, 0, NULL, NULL);
    cout << "received : " <<  buf;
    //for (int i = 0; i < sizeof(buf); i++) enc_buf[i] = buf[i];
    //Mat jpgimage = imdecode(enc_buf, CV_LOAD_IMAGE_COLOR);
    //imwrite("jpgimg.jpg", jpgimage);
    cin.get();

    // winsock2の終了処理
    WSACleanup();

    cin.get();
    return 0;
}

実行結果

サーバイメージ説明

試したこと

memset(buf, 0, BUFFER_SIZE);から,memset(buf, 0, 1);にした(メモリの総数を減らしたらどうなるかを試した).
→結果:同じ
len = sizeof(client)と,バッファのサイズに関しては,手を付けていない.

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

・Visual Studio2015 C++
・OpenCV3.1 ←Nugetから入手
・winsock2.h

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

>・クライアント側で,文字が最初の3文字しか受け取れない
recvfrom命令はその時点でバッファに格納されているデータを読み出す命令です。指定したサイズのデータを読み出す命令ではありません。1回のsendto呼び出しで送信したデータが複数回に分かれて受信される事もありますし、逆に2回のsendto呼び出しで送信したデータが1回で受信される事もあります。必要なデータが揃うまで、recvfromを複数回呼び出してデータを結合するように修正して下さい。

ただ3バイトだけというのは、それはそれで異常です。見てみると「cout << "received : " <<  buf;」で出力していますが、4バイト目に0x00が格納されていませんか?C++ではバイト列中に含まれる0x00を文字列の終端として扱うので、バイナリデータを文字列系のAPIでは扱えませんよ。

・バッファのサイズを大きくすると,オーバーフローとなってしまう.
スタックオーバーフローのことですか?バッファをスタック上に作成しているようですが、スタックのサイズは通常1Mバイト程度でしかありません。ビルド時の設定で増やすことも出来ますが、スタック領域ではなくヒープ領域に確保するように直した方が良いでしょう。

・サーバ側の,  len = sizeof(client);  の意味がわからない.
socket APIはIPv4専用のAPIではありません。それ以外の様々な通信プルトコルでも使用します。そのためアドレスを表す構造体のサイズも固定ではなく、メモリサイズを引数として渡すように設計されています。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/11 17:25 編集

    ご回答ありがとうございます!
    知りたいことを全て教えてくださって正直びっくりしました.
    >ただ3バイトだけというのは、それはそれで異常です。見てみると「cout << "received : " << buf;」で出力していますが、4バイト目に0x00が格納されていませんか?
    →全くもってそのとおりでした.バイナリデータにしてだすと,FF D8 FF E0 00とあり,0x00がありました!ありがとうございます!
    >スタックオーバーフローのことですか?バッファをスタック上に作成~
    →この件に関しては,mallocというのを使って解決しようと思います!
    >socket APIはIPv4専用のAPIではありません。
    →なるほど!たしかにそうですね!教えていただきありがとうございます!

    おかげで,画像を送信することに成功しました!本当にありがとうございました!!!

    キャンセル

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

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

関連した質問

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

  • Visual Studio

    1699questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • Windows

    1365questions

    Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

  • OpenCV

    970questions

    OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

  • TCP

    154questions

    TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

  • UDP

    55questions

    UDP(User Datagram Protocol)とは、トランスポート層のプロトコルであり、コネクション型のデータサービスです。IPネットワーク上の別のホストにコンピュータのアプリケーションがメッセージを送ることができ、転送チャンネルやデータ経路を設定する必要はありません。TCPに比べて高速であるが、信頼性が薄いという特徴があります。