ページ 1 / 1
型変換
Posted: 2018年4月06日(金) 00:25
by にこよん
winsock通信で数字を送りたいのですがchar型しか送受信できないので変換する必要があります
ただ、変換しても数字に戻した時に数がおかしくなる時があります
どのように改善すればいいでしょうか?
コード:
//エンコード時
memcpy(press_data, &version, 1); //バージョン情報をコピー(unsigned char)
memcpy(&press_data[1], &id, 2); //識別IDをコピー(short int)
memcpy(&press_data[3], &m_data_size, 4); //元データのサイズをコピー
//デコード時
memcpy(&version, press_data, 1); //バージョン情報をコピー
memcpy(&id, &press_data[1], 2); //識別IDをコピー
memcpy(&m_data_size, &press_data[3], 4); //元データのサイズをコピー
[環境]win10,visualstudio2017, VC++
Re: 型変換
Posted: 2018年4月06日(金) 00:48
by box
登場している変数名の定義ぐらいは見せていただきたいです。
Re: 型変換
Posted: 2018年4月06日(金) 01:35
by にこよん
ご指摘ありがとうございます
どこまでお伝えすればいいのかが分からないので言っていただけると助かります
(最初からすべての部分をのせると読みにくそうだったので省略しました)
定義したものではなく関数の引数なのでどのように書けばいいのかわからず....
このあたりで大丈夫でしょうか?
コード:
//データを64進数文字列に圧縮変換する
class STR_ENCODE {
uLong m_data_size; //データのサイズ
uLong m_press_size; //圧縮後のデータのサイズ
Bytef *m_buffer; //データを保存するメモリのポインタ
Bytef *m_press_buffer; //圧縮データを保存するメモリのポインタ
unsigned int m_write_size; //書き込み中のサイズ
public:
//コンストラクタ
STR_ENCODE(int size);
//デトラクタ
~STR_ENCODE();
//保存するデータをメモリにコピーする
void wcpy(void const* Src, unsigned int Size);
//データを圧縮して取得する
int write(unsigned char version, short int id, char press_data[]);//←エンコードのはこいつ
};
//64進数文字列からデータに展開変換する
class STR_DECODE {
uLong m_data_size; //データのサイズ
uLong m_press_size; //圧縮後のデータのサイズ
Bytef *m_buffer; //データを保存するメモリのポインタ
Bytef *m_press_buffer; //圧縮データを保存するメモリのポインタ
unsigned int m_write_size; //書き込み中のサイズ
public:
//コンストラクタ
STR_DECODE(char press_data[], int size, unsigned char *version, short int *id);//←デコードはこいつ
//デトラクタ
~STR_DECODE();
//読み込んだデータをコピーする
void rcpy(void *Src, unsigned int Size);
//データを展開して取得する
int read();
};
コード:
//デコード関数の内容↓
STR_DECODE::STR_DECODE(char press_data[],int size, unsigned char *version, short int *id) { //コンストラクタ
memcpy(version, press_data, 1); //バージョン情報をコピー
memcpy(id, &press_data[1], 2); //識別IDをコピー
memcpy(&m_data_size, &press_data[3], 4); //元データのサイズをコピー
//version = press_data[0]; //バージョン情報をコピー
//id = press_data[1]; //識別IDをコピー
//m_data_size = press_data[3]; //元データのサイズをコピー
//m_data_size = ((long)press_data[6] << 24) | ((long)press_data[5] << 16) | ((long)press_data[4] << 8) | (long)press_data[3];
m_press_size = size -7;
for (int i =0; i < m_press_size; i++)
press_data[i] = press_data[i + 7]; //7バイト分前に詰める
m_buffer = (Bytef*)malloc(m_data_size); //保存するデータより十分大きいメモリを確保
if (!m_buffer) {
WSA_ERR("メモリの確保に失敗しました"); //エラーメッセージ
return;
}
m_press_buffer = (Bytef*)malloc(m_press_size); //圧縮後のデータを保存するメモリを確保する
if (!m_press_buffer) {
WSA_ERR("メモリの確保に失敗しました"); //確保に失敗すればエラーメッセージ
return;
}
m_write_size = 0; //書き込み中サイズの初期化
for (unsigned long i = 0; i < m_press_size; i++) m_press_buffer[i] = press_data[i] + 128;
};
Re: 型変換
Posted: 2018年4月06日(金) 09:43
by かずま
にこよん さんが書きました: ↑7年前
winsock通信で数字を送りたいのですがchar型しか送受信できないので変換する必要があります
ただ、変換しても数字に戻した時に数がおかしくなる時があります
「おかしくなる時があります」だけでは情報不足です。
実際にどんな値を送信したら、受信した値がどうなったかを書きましょう。
winsock通信ということですが、受信の
n = recv(sock, press_data, m, 0);
で、n や m は 7以上になっていますか?
Re: 型変換
Posted: 2018年4月06日(金) 10:32
by にこよん
nは普通にサイズを表してくれています
mはこのように書いています
コード:
//データ通信で使用できる最大サイズ
#define MAX_DATA_SIZE 262144
コード:
char buf[MAX_DATA_SIZE];
memset(buf, 0, sizeof(buf));
int n = recv(sock, buf, sizeof(buf), 0);
てっきりmemcpyを使うこと自体が間違いなのかと思っていたのですが、そうではないのでしょうか?
一応送受信のプログラムを貼っておきます
必要なければスルーでお願いします
(見ずらい貼り方ですみません)
//ヘッダ
コード:
class SERVER {
SOCKET sock_lobby; //通信要請を受け取るソケット
sockaddr_in addr; //ロビーのアドレス情報
SOCKET sock; //クライアントとの通信を行うソケット
sockaddr_in client_addr; //クライアント情報
SOCKET udp_sock;
sockaddr_in udp_addr; //ロビーのアドレス情報
public:
//コンストラクタ
SERVER();
//サーバーのスタートアップ処理
int Stert();
//クライアントからの通信を受け取る
int Accept();
//データを送信する
int Send(const TCHAR *data, const int size);
//データを受信する
int Recv(char data[]);
//UDP通信のスタートアップ処理
int UDPstert();
//データを送信する
int UDPsend(const char data[]);
//データを受信する
int UDPrecv(char data[1024]);
//UDP通信を終了する
int UDPend();
};
class CLIENT {
struct sockaddr_in server_addr;
SOCKET sock;
public:
//コンストラクタ
CLIENT();
//データをサーバーに送信する
int Send(const TCHAR *data, int size);
//データをサーバーから受信する
int Recv(char data[]);
};
//cpp
コード:
SERVER::SERVER() {
}
int SERVER::Stert() {
sock_lobby = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //ソケットの作成
if (sock_lobby == INVALID_SOCKET) {
WSA_ERR("ソケットの作成に失敗しました(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
else AddTempLog("ロビーソケットを作成しました");
bool yes = true; //1が登録されたポインタを作成
setsockopt(sock_lobby, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(yes)); //TIME_WAIT状態への対策(ソケットオプションの設定
addr.sin_family = AF_INET; //ソケットの設定をする
addr.sin_port = htons(PORT); //使用するポート
addr.sin_addr.S_un.S_addr = INADDR_ANY; //接続するアドレス
if (bind(sock_lobby, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
WSA_ERR("ローカルアドレスとソケットの関連付けに失敗しました(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
else AddTempLog("ローカルアドレスとソケットの関連付けが完了しました");
u_long val = 1; //ノンブロッキング(非同期通信)に設定する
ioctlsocket(sock_lobby, FIONBIO, &val);
if (listen(sock_lobby, 5) != 0) { //TCPクライアントからの接続要求を待てる状態にする
WSA_ERR("ソケットをリッスン状態にできませんでした(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
else AddTempLog("ソケットを通信受付状態にしました");
AddTempLog("ロビーソケットの初期化が正常に終了しました port=%d", PORT);
return COMM_LIB_NO_ERROR;
}
int SERVER::Accept() {
int len = sizeof(client_addr); //TCPクライアントからの接続要求を受け付ける
sock = accept(sock_lobby, (struct sockaddr *)&client_addr, &len);
if (sock == INVALID_SOCKET) { //ソケットの値が正常ではない
if (WSAGetLastError() != WSAEWOULDBLOCK) { //要請がない場合ではなかったら
WSA_ERR("クライアントからの接続に失敗しました(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
}
else { //接続要請があれば
hostent *host = gethostbyaddr((const char *)&client_addr.sin_addr, sizeof(addr.sin_addr), AF_INET);
if (host == NULL) { //失敗したらエラーを表示して終了
WSA_ERR("ホスト情報の取得に失敗しました(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
AddServerLog(" accepted connection from [%s], ip=%s, port=%d", host->h_name, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
return 1;
}
return COMM_LIB_NO_ERROR;
}
int SERVER::Recv(char data[]) {
char buf[MAX_DATA_SIZE];
memset(buf, 0, sizeof(buf));
int n = recv(sock, buf, sizeof(buf), 0);
if (n < 0) {
if (WSAGetLastError() != WSAEWOULDBLOCK) { //何らかのエラーが発生している
WSA_ERR("データの受信に失敗しました(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
}
else if (n != 0) { //データが届いたら
AddTempLog("データを受信しました-%d「%.64s」", n, buf);
sprintf_s(data, 1024, "%s", buf);
return n;
}
return COMM_LIB_NO_ERROR;
}
int SERVER::Send(const TCHAR *data, int size) {
if (send(sock, data, /*strlen(data)*/size, 0) < 1) {
WSA_ERR("データの送信に失敗しました(%d)", WSAGetLastError());
closesocket(sock); //TCPセッションの終了
memset(&sock, 0, sizeof(sock));
return COMM_LIB_ERROR;
}
else AddTempLog("データを送信しました「%.64s」", data);
closesocket(sock); //TCPセッションの終了
memset(&sock, 0, sizeof(sock));
return COMM_LIB_NO_ERROR;
}
CLIENT::CLIENT() {
}
int CLIENT::Recv(char data[]) {
char buf[MAX_DATA_SIZE];
memset(buf, 0, sizeof(buf));
int n = recv(sock, buf, sizeof(buf), 0);
if (n < 0) {
if (WSAGetLastError() != WSAEWOULDBLOCK) { //何らかのエラーが発生している
WSA_ERR("データの受信に失敗しました(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
}
else if (n != 0) { //データが届いたら
AddTempLog("データを受信しました-%d「%.64s」", n, buf);
closesocket(sock); //TCPセッションの終了
memset(&sock, 0, sizeof(sock));
sprintf_s(data, n, "%s", buf);
return n;
}
return COMM_LIB_NO_ERROR;
}
int CLIENT::Send(const TCHAR *data, int size) {
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //ソケットの作成
if (sock == INVALID_SOCKET) {
WSA_ERR("ソケットの作成に失敗しました(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
else AddTempLog("ソケットを作成しました");
server_addr.sin_family = AF_INET; //ソケットの設定をする
server_addr.sin_port = htons(PORT); //使用するポート
hostent *host = gethostbyname(host_name); //リリース時にはホストIPを使う
if (host == NULL) {
WSA_ERR("サーバー情報がありません");
return COMM_LIB_ERROR;
}
server_addr.sin_addr.S_un.S_addr = *(unsigned int *)host->h_addr_list[0]; //サーバーIPアドレスを取得する
AddTempLog("サーバー情報の取得に成功しました");
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {//サーバに接続を試みる
WSA_ERR("サーバーに接続できませんでした(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
else AddTempLog("サーバーに接続しました");
if (send(sock, data, size, 0) < 1) {
WSA_ERR("データの送信に失敗しました(%d)", WSAGetLastError());
return COMM_LIB_ERROR;
}
else AddTempLog("データの送信に成功しました");
return COMM_LIB_NO_ERROR;
}
Re: 型変換
Posted: 2018年4月06日(金) 10:40
by にこよん
数は正確には
2177584206
になっています
送る前(エンコード前)の正しい数は4です
※この数は最初の7バイトを含まないデータサイズです
Re: 型変換
Posted: 2018年4月06日(金) 11:40
by かずま
version, id, m_data_size のすべての値を書いてください。
例えば、version = 'A', id = 63, m_data_size = 4 だとすると、
press_data は、{ 0x41, 0x3f, 0x00, 0x04, 0x00, 0x00, 0x00 } の
7バイトになり、それが送信され、受信されると
buf にその値が入ります。
それを data にコピーするところで、sprintf_s(data, 1024, "%s", buf);
または、sprintf_s(data, n, "%s", buf); を使っていますが、
これだと、data には { 0x41, 0x3f, 0x00 } しかコピーされません。
なぜなら、sprintf の "%s" は文字列を扱うので、
'\0' までしか参照しないからです。
id = 258 の場合、press_data は、
{ 0x41, 0x02, 0x01, 0x04, 0x00, 0x00, 0x00 } となって、
{ 0x41, 0x02, 0x01, 0x04, 0x00 } が data にコピーされます。
受信データをすべてコピーしたいのなら、
memcpy(data, buf, 1024); または
memcpy(data, buf, n); にしましょう。
Re: 型変換
Posted: 2018年4月06日(金) 15:01
by にこよん
ご回答ありがとうございます
テストではこのようにしています
version = 1, id = 1
(version = '1'と間違えているわけではなく1を入れています)
> 受信データをすべてコピーしたいのなら、
> memcpy(data, buf, 1024); または
> memcpy(data, buf, n); にしましょう。
2ヶ所下のほうに書き換えて実行してみたのですが、結果は変わらずでした...
Re: 型変換
Posted: 2018年4月06日(金) 15:17
by にこよん
最初のところにエンコード等のコードを乗せていなかったので乗せます
必要なければスルーでお願いしますm(__)m
h
コード:
#ifndef ZLIB_H
#pragma comment(lib, "zlib.lib") //Zlibをリンクする
#include <zlib.h> //Zlibをインクルードする
#endif
//データを64進数文字列に圧縮変換する
class STR_ENCODE {
uLong m_data_size; //データのサイズ
uLong m_press_size; //圧縮後のデータのサイズ
Bytef *m_buffer; //データを保存するメモリのポインタ
Bytef *m_press_buffer; //圧縮データを保存するメモリのポインタ
unsigned int m_write_size; //書き込み中のサイズ
public:
//コンストラクタ
STR_ENCODE(int size);
//デトラクタ
~STR_ENCODE();
//保存するデータをメモリにコピーする
void wcpy(void const* Src, unsigned int Size);
//データを圧縮して取得する
int write(unsigned char version, short int id, char press_data[]);
};
//64進数文字列からデータに展開変換する
class STR_DECODE {
uLong m_data_size; //データのサイズ
uLong m_press_size; //圧縮後のデータのサイズ
Bytef *m_buffer; //データを保存するメモリのポインタ
Bytef *m_press_buffer; //圧縮データを保存するメモリのポインタ
unsigned int m_write_size; //書き込み中のサイズ
public:
//コンストラクタ
STR_DECODE(char press_data[], int size, unsigned char *version, short int *id);
//デトラクタ
~STR_DECODE();
//読み込んだデータをコピーする
void rcpy(void *Src, unsigned int Size);
//データを展開して取得する
int read();
};
cpp
コード:
STR_ENCODE::STR_ENCODE(int size) : m_data_size(size) { //コンストラクタ
m_buffer = (Bytef*)malloc(m_data_size); //保存するデータより十分大きいメモリを確保
if (!m_buffer) WSA_ERR("メモリの確保に失敗しました"); //エラーメッセージ
uLong press_buffer_size = compressBound(m_data_size); //圧縮に必要なサイズを計算
if (m_data_size > press_buffer_size) { //計算結果があっているか確認する
WSA_ERR("press size error (%lu -> %lu)", m_data_size, press_buffer_size); //あっていなければエラーメッセージ
}
m_press_buffer = (Bytef*)malloc(press_buffer_size); //圧縮後のデータを保存するメモリを確保する
if (!m_press_buffer) WSA_ERR("メモリの確保に失敗しました"); //確保に失敗すればエラーメッセージ
m_write_size = 0; //書き込み中サイズの初期化
};
STR_ENCODE::~STR_ENCODE() { //デストラクタ
free(m_buffer); //確保したメモリの解放
free(m_press_buffer); //確保したメモリの開放
}
void STR_ENCODE::wcpy(void const* Src, unsigned int Size) {
if (m_write_size + Size > m_data_size) { //保存データが確保したメモリのデータより大きかったら
WSA_ERR("エンコードするデータが大きすぎます"); //エラーメッセージ
return; //終了
}
memcpy(m_buffer + m_write_size, Src, Size); //データをメモリにコピーする
m_write_size += Size; //保存した分だけメモリを進める
}
int STR_ENCODE::write(unsigned char version, short int id, char press_data[]) { //データを圧縮してファイルに書き込む
if (m_write_size != m_data_size) {
WSA_ERR("保存データのサイズが一致しませんでした"); //エラーメッセージ
WSA_ERR("詳細 : %lu -> %lu", m_write_size, m_data_size); //詳細をエラーメッセージ
return COMM_LIB_ERROR; //エラーで終了する
}
uLongf press_size;
int z_err = compress2(m_press_buffer, &press_size, m_buffer, m_data_size, Z_BEST_SPEED); //データの圧縮
if (z_err != Z_OK) { //エラーコードが返ってきたら
WSA_ERR("データの圧縮に失敗しました"); //エラーメッセージ
switch (z_err) {
case Z_MEM_ERROR:
WSA_ERR("Z_MEM_ERROR エラーが発生しました");
break;
case Z_BUF_ERROR:
WSA_ERR("Z_BUF_ERROR メモリに十分な空き容量がありません");
break;
case Z_STREAM_ERROR:
WSA_ERR("Z_STREAM_ERROR 圧縮レベルが不明です");
break;
default:
WSA_ERR("Z_ERROR 不明なエラーが発生しました");
break;
}
return COMM_LIB_ERROR; //エラーで終了する
}
for (unsigned long i = 0; i < press_size; i++) press_data[i] = m_press_buffer[i] - 128; //圧縮したデータを変換コピーする
for (int i = press_size - 1; i >= 0; i--)
press_data[i + 7] = press_data[i]; //最初に7バイトの空きを作る
memcpy(press_data, &version, 1); //バージョン情報をコピー
memcpy(&press_data[1], &id, 2); //識別IDをコピー
memcpy(&press_data[3], &m_data_size, 4); //元データのサイズをコピー
//press_data[0] = version; //バージョン情報をコピー
//press_data[1] = id; //識別IDをコピー
//press_data[3] = (char)m_data_size; //元データのサイズをコピー
return int(press_size) + 7;
}
STR_DECODE::STR_DECODE(char press_data[],int size, unsigned char *version, short int *id) { //コンストラクタ
memcpy(version, press_data, 1); //バージョン情報をコピー
memcpy(id, &press_data[1], 2); //識別IDをコピー
memcpy(&m_data_size, &press_data[3], 4); //元データのサイズをコピー
//version = press_data[0]; //バージョン情報をコピー
//id = press_data[1]; //識別IDをコピー
//m_data_size = press_data[3]; //元データのサイズをコピー
//m_data_size = ((long)press_data[6] << 24) | ((long)press_data[5] << 16) | ((long)press_data[4] << 8) | (long)press_data[3];
m_press_size = size - 7;
for (int i =0; i < m_press_size; i++)
press_data[i] = press_data[i + 7]; //7バイト分前に詰める
m_buffer = (Bytef*)malloc(m_data_size); //保存するデータより十分大きいメモリを確保
if (!m_buffer) {
WSA_ERR("メモリの確保に失敗しました"); //エラーメッセージ
return;
}
m_press_buffer = (Bytef*)malloc(m_press_size); //圧縮後のデータを保存するメモリを確保する
if (!m_press_buffer) {
WSA_ERR("メモリの確保に失敗しました"); //確保に失敗すればエラーメッセージ
return;
}
m_write_size = 0; //書き込み中サイズの初期化
for (unsigned long i = 0; i < m_press_size; i++) m_press_buffer[i] = press_data[i] + 128;
};
STR_DECODE::~STR_DECODE() { //デストラクタ
free(m_buffer); //確保したメモリの解放
free(m_press_buffer); //確保したメモリの開放
}
void STR_DECODE::rcpy(void *Src, unsigned int Size) {
if (m_write_size >= m_data_size) {
WSA_ERR("データサイズが確保分を超えました"); //エラーメッセージ
return; //戻る
}
memcpy(Src, m_buffer + m_write_size, Size); //メモリからデータをコピーする
m_write_size += Size; //保存した分だけメモリを進める
}
int STR_DECODE::read() {
int z_err = uncompress(m_buffer, &m_data_size, m_press_buffer, m_press_size); //データを展開
if (z_err != Z_OK) {
WSA_ERR("データの展開に失敗しました"); //エラーメッセージ
switch (z_err) {
case Z_MEM_ERROR:
WSA_ERR("Z_MEM_ERROR エラーが発生しました");
break;
case Z_BUF_ERROR:
WSA_ERR("Z_BUF_ERROR メモリに十分な空き容量がありません");
break;
case Z_DATA_ERROR:
WSA_ERR("Z_DATA_ERROR データが破損しています");
break;
default:
WSA_ERR("Z_ERROR 不明なエラーが発生しました");
break;
}
return COMM_LIB_ERROR; //エラーで終了する
}
return COMM_LIB_NO_ERROR; //正常終了
}
Re: 型変換
Posted: 2018年4月06日(金) 17:18
by かずま
コード:
void dump(void *vp, int n)
{
unsigned char *p = (unsigned char *)vp;
for (int i = 0; i < n; i++) printf(" %02x", p[i]);
putchar('\n');
}
上記の関数を追加し、
send(sock, data, size, 0); の前に dump(data, 7); を
recv(sock, buf, sizeof(buf), 0); の後に dump(buf, 7); を
入れて、実行結果を教えてください。
Re: 型変換
Posted: 2018年4月07日(土) 00:15
by にこよん
サーバー側(recv
f8 81 4b 4e 4c cb 81
クライアント側(send
64 fa 5d 00 13 00 00
でした
ほんとですね全くデータが違う....
いまいち適切なデータの確認方法が分かってなかったので見方が分かりましたm(__)m
ただ、送る直前と受け取った直後なのでデータが変わっている理由が分からないです...
TCP通信だからデータが破損ではない...?
Re: 型変換
Posted: 2018年4月07日(土) 00:57
by にこよん
もしかして、マルチバイト文字セットを使っているのが原因だったりしますでしょうか...?
それか下のやつを定義していることとか...?
#define _WINSOCK_DEPRECATED_NO_WARNINGS //警告を消す
Re: 型変換
Posted: 2018年4月07日(土) 01:45
by かずま
version = 1, id = 1, m_data_szie = 4 なら
送信データは、01 01 00 04 00 00 00 となるはずです。
Visuual Studioe 2017 を使っているのなら、
ブレークポイントを設定し、ステップ実行で変数の値の変化を確認しながら、
デバッグできるはずです。
そういうことができないのなら、printf をあちこちに入れて、
変数の値の変化がどうなっているのかを確認してください。
デバッグの基本です。
Re: 型変換
Posted: 2018年4月07日(土) 17:15
by にこよん
ブレークポイントからデバッグはやっていたのですが
1バイト目の中身が\x1と表示されそれ以降が見れなかったのでどうすればいいのかわからずにいろいろ調べていました
とりあえず教えて頂いた関数と中に入るべき数の正解の数を利用して原因を探ってみますm(__)m
Re: 型変換 (解決)
Posted: 2018年4月08日(日) 02:15
by にこよん
原因は教えていただいたsprintf_sでの文字コピーと
decode関数で引数を直接編集していることのようでした
dump関数はこのまま残しておいて、また使えるようにしておきます
かずまさん、ご丁寧に教えていただきありがとうございましたm(__)m