ページ 1 / 1
チャットプログラムのバグ
Posted: 2018年4月17日(火) 20:58
by fabersid
[1] 質問文
[1.1] 作っているもの:チャットプログラム(ただしソケットを使わない)
[1.2] どのように取り組んだか(後述)
[1.3] ファイル内容を表示するときにごみデータが表示される
[2] 環境
[2.1] OS:Windows
[2.2] コンパイラ名:Borand C++
バグった時の画面
再現性は少ない
display_file関数にバグがあることは確かです。
コード:
ゲストさんが入室しました。
ゲスト>>Hello,C++
ゲスト>>This is bug.
・ゲスト>>
4行目の1文字目に「・」が入り込んでいる
コード:
#define WIN32_LEAN_AND_MEAN // Windows ヘッダーから使用されていない部分を除外します。
#define LOG_FILE ".dll"
#define KEY 0
#include <windows.h>
#include <string> //ヘッダファイルインクルード
#include <iostream> //標準入出力(C++)
#include <fstream> //ファイル入出力
#include <stdlib.h> //標準ライブラリ…system()
#include <algorithm>
using namespace std; //名前空間指定
void add_file(const string);
void display_file();
void history_reset();
string ango(const string);
int main(){
string user="ゲスト"; //ローカル変数として、str を生成
string text="";
string ango;
cerr << "ユーザー名を入力:";
cin >> user;
add_file(user + "さんが入室しました。");
while("EXIT"!=text){
if(text!=""){
add_file(user+">>"+text);
}
display_file();
cerr << user << ">>";
history_reset();
getline(cin, text);
}
add_file(user + "さんが退室しました。");
}
void add_file(const string a){
if(a=="")return;
ofstream ofs(LOG_FILE,ios::binary|ios::app);
ofs << ango(a + "\r\n");
ofs.close();
}
void display_file(){
system("cls");
ifstream ifs(LOG_FILE,ios::binary);
if(!ifs){ return; } //ファイルが開けたか確認
char buf[256]; //256バイト分のバッファ
while(!ifs.eof()){
ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
cout << ango(buf); //標準出力に出力してみる
}
ifs.close();
}
void history_reset(){
#define VK_MENU 0x12/*Alt*/
#define VK_F7 0x76/*F7*/
// キーの押し下げをシミュレートする。
keybd_event( VK_MENU, 0, 0, 0);
// キーの押し下げをシミュレートする。
keybd_event( VK_F7, 0, 0, 0);
system("timeout /t 1 /NOBREAK>nul");
// キーの解放をシミュレートする。
keybd_event( VK_F7, 0, KEYEVENTF_KEYUP, 0);
// キーの解放をシミュレートする。
keybd_event( VK_MENU, 0, KEYEVENTF_KEYUP, 0);
}
string ango(const string tmp){
string ret=tmp;
for(int i = 0; i < (int)ret.size(); ++i){
ret[i] = ret[i] ^ KEY;
}
return ret;
}
オフトピック
XOR暗号を使う理由はファイルを改ざんされにくくするためです。
Re: チャットプログラムのバグ
Posted: 2018年4月17日(火) 23:57
by かずま
ifs.read で常に 256バイト読めるわけではありません。
読む前に buf を初期化しましょう。
コード:
void display_file(){
system("cls");
ifstream ifs(LOG_FILE,ios::binary);
if(!ifs){ return; } //ファイルが開けたか確認
while(!ifs.eof()){
char buf[256] = ""; //256バイト分のバッファ
ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
cout << ango(buf); //標準出力に出力してみる
}
ifs.close();
}
Re: チャットプログラムのバグ
Posted: 2018年4月18日(水) 02:16
by かずま
256バイト読めたときにも '\0' の分が必要です。
コード:
char buf[257] = ""; //256バイトと '\0' のバッファ
ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
Re: チャットプログラムのバグ
Posted: 2018年4月19日(木) 08:49
by かずま
毎回、buf全体を初期化するということを避けるやり方もあります。
コード:
char buf[256+1]; //256バイトと '\0 'の分のバッファ
while(!ifs.eof()){
ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
buf[ifs.gcount()] = '\0';
cout << ango(buf); //標準出力に出力してみる
}
ところで、history_reset() は何のためにあるのでしょうか?
プロンプトの ">>" が表示された後、1秒間キー入力を受け
付けないのは不便ではありませんか?
Re: チャットプログラムのバグ
Posted: 2018年4月19日(木) 19:48
by 通りすがりの......
history_reset関数はfabersidさんの意図した結果をもたらしません。
cmd.exeで実行するうえで連投防止をしようとしているようですが、
cmd.exeがうまくキーコードを受け取らない時があります。
できるならctrlキーの制御もしたほうがいいかと。
右クリックで貼り付けができるcmdもあるらしいです。
私には技術が足りません
このサイトのコーダーさんに私からもお願いします。
Re: チャットプログラムのバグ
Posted: 2018年4月20日(金) 22:28
by fabersid
追加で実現したい機能
- history_reset関数を実現する
- 連投防止
- 荒らし追放用機能追加
- 人数表示(system関数で実現)
発生中のエラー及び警告
コード:
エラー E2285 text._ver.2.cpp 126: 'string::operator =(char *)' に一致するものが見つからない(関数 checkFileExistence(const string) )
エラー E2379 text._ver.2.cpp 126: ステートメントにセミコロン(;)がない(関数 checkFileExistence(const string) )
エラー E2285 text._ver.2.cpp 127: 'ifstream::basic_ifstream(const string)' に一致するものが見つからない(関数 checkFileExistence(const string) )
警告 W8057 text._ver.2.cpp 129: パラメータ 'str' は一度も使用されない(関数 checkFileExistence(const string) )
エラー E2285 text._ver.2.cpp 136: 'ofstream::basic_ofstream(const string)' に一致するものが見つからない(関数 user_make(const string) )
警告 W8004 text._ver.2.cpp 138: 'ofs' に代入した値は使われていない(関数 user_make(const string) )
現在のコード(バグ未修正・#2~#5既読)
コード:
#define WIN32_LEAN_AND_MEAN // Windows ヘッダーから使用されていない部分を除外します。
#define LOG_DIR "DATA.{BB06C0E4-D293-4f75-8A90-CB05B6477EEE}"
#define LOG_FILE LOG_DIR"\\LOG.dll"
//define DATA FILEs
/*
DATA.{BB06C0E4-D293-4f75-8A90-CB05B6477EEE}
LOG.dll
Users
username.dll
・
・
・
*/
#define KEY 123
#include <windows.h>
#include <sys\stat.h> //フォルダの確認(stat)
#include <direct.h> //フォルダの作成(_mkdir)
#include <string> //ヘッダファイルインクルード
#include <iostream> //標準入出力(C++)
#include <fstream> //ファイル入出力
#include <stdio.h>
#include <stdlib.h> //標準ライブラリ…system()
#include <algorithm>
using namespace std; //名前空間指定
bool user_make(const string);
bool command(const string);
bool checkFileExistence(const string);
void add_file(const string);
void display_file();
void history_reset();
string ango(const string);
int main(){
string text="";
string ango;
string user;
do{
user="";
cerr << "ユーザー名を入力:";
cin >> user;
}while(!user_make(user));
struct stat statBuf;
if (stat(LOG_DIR, &statBuf) != 0){
if (_mkdir(LOG_DIR) != 0){
printf("ディレクトリを作成できませんでした。\n。");
printf("異常終了\n");
return 1;
}
}
if (stat(LOG_DIR"\\Users", &statBuf) != 0){
if (_mkdir(LOG_DIR"\\Users") != 0){
printf("ディレクトリを作成できませんでした。\n。");
printf("異常終了\n");
return 1;
}
}
cout << "退室するときはEXITと打ってください。";
add_file(user + "さんが入室しました。");
while("EXIT"!=text){
if(text!=""){
if(!command(text)){
add_file(user+">>"+text);
}
}
display_file();
cerr << user << ">>";
history_reset();
getline(cin, text);
history_reset();
}
add_file(user + "さんが退室しました。");
return 0;
}
void add_file(const string a){
if(a=="")return;
ofstream ofs(LOG_FILE,ios::binary|ios::app);
ofs << ango(a + "\r\n");
ofs.close();
}
void display_file(){
system("cls");
ifstream ifs(LOG_FILE,ios::binary);
if(!ifs){ return; } //ファイルが開けたか確認
while(!ifs.eof()){
char buf[257]=""; //256バイト分のバッファ
ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
cout << ango(buf); //標準出力に出力してみる
}
ifs.close();
}
void history_reset(){
#define VK_MENU 0x12/*Alt*/
#define VK_F7 0x76/*F7*/
// キーの押し下げをシミュレートする。
keybd_event( VK_MENU, 0, 0, 0);
// キーの押し下げをシミュレートする。
keybd_event( VK_F7, 0, 0, 0);
system("timeout /t 1 /NOBREAK>nul");
// キーの解放をシミュレートする。
keybd_event( VK_F7, 0, KEYEVENTF_KEYUP, 0);
// キーの解放をシミュレートする。
keybd_event( VK_MENU, 0, KEYEVENTF_KEYUP, 0);
}
string ango(const string tmp){
string ret=tmp;
for(int i = 0; i < (int)ret.size(); ++i){
ret[i] = ret[i] ^ KEY;
}
return ret;
}
//https://qiita.com/takahiro_itazuri/items/e999ae24ab34b2756b04
#include<string>
#include<fstream>
#include<iostream>
bool checkFileExistence(string str){
str=LOG_DIR"\\Users\\"s+str;
ifstream ifs(str);
return ifs.is_open();
}
bool user_make(const string userName){
if(checkFileExistence(userName)){
cout << userName << "は使用済みです。";
return false;
}
ofstream ofs(userName);
return true;
}
bool user_delete(const string userName){
if(remove((LOG_DIR"\\Users\\"+userName).c_str()) != 0 ){
fprintf(stderr,"%sは存在しません",userName.c_str());
return false;
}
return true;
}
bool command(const string text){
#define cmd_exec(x,y) {if(text.substr(0,strlen(x))==x){y(text.substr(strlen(x)));return true;}}
//x=string y=function
cmd_exec("/ban ",user_delete);
#undef cmd_exec
return false;
}
Re: チャットプログラムのバグ
Posted: 2018年4月21日(土) 15:27
by かずま
コード:
29行目: bool checkFileExistence(string); // const を削除
126行目: str=LOG_DIR"\\Users\\"+str; // + の前の s を削除
127行目: ifstream ifs(str.c_str()); // .c_str() を追加
136行目: ofstream ofs(userName.c_str()); // .c_str() を追加
関数の引数は値渡しなので、const string& や const string* なら
「呼び出し元の文字列を変更しない」という重要な意味が const に
ありますが、const string では無意味です。
ifstream や ofstream のコンストラクタの第1引数に
string が使えるようになったのは C++11からです。
Re: チャットプログラムのバグ
Posted: 2018年4月24日(火) 21:39
by fabersid
! | メッセージ from: fabersid |
history_reset関数の不具合が未解決です。 |
参考:
コマンドプロントの閉じるボタンの無効化のやり方 by aberu » 5年前
無題 by 恐 » 8年前
#7の既読後コードを追加し強制終了されることによる
不具合が起きにくくなりました。
コード:
#define WIN32_LEAN_AND_MEAN // Windows ヘッダーから使用されていない部分を除外します。
#define LOG_DIR "DATA.{BB06C0E4-D293-4f75-8A90-CB05B6477EEE}"
#define LOG_FILE LOG_DIR"\\LOG.dll"
//define DATA FILEs
/*
DATA.{BB06C0E4-D293-4f75-8A90-CB05B6477EEE}
LOG.dll
Users
username
・
・
・
*/
#define KEY 123
#include <windows.h>
#include <sys\stat.h> //フォルダの確認(stat)
#include <direct.h> //フォルダの作成(_mkdir)
#include <string> //ヘッダファイルインクルード
#include <iostream> //標準入出力(C++)
#include <fstream> //ファイル入出力
#include <stdio.h>
#include <stdlib.h> //標準ライブラリ…system()
#include <algorithm>
using namespace std; //名前空間指定
bool user_make(const string);
bool command(const string);
bool checkFileExistence(string);
void add_file(const string);
void display_file();
void history_reset();
string ango(const string);
int main(){
string text="";
string ango;
string user;
do{
user="";
cerr << "ユーザー名を入力:";
cin >> user;
}while(!user_make(user));
struct stat statBuf;
if (stat(LOG_DIR, &statBuf) != 0){
if (_mkdir(LOG_DIR) != 0){
printf("ディレクトリを作成できませんでした。\n。");
printf("異常終了\n");
return 1;
}
}
if (stat(LOG_DIR"\\Users", &statBuf) != 0){
if (_mkdir(LOG_DIR"\\Users") != 0){
printf("ディレクトリを作成できませんでした。\n。");
printf("異常終了\n");
return 1;
}
}
const char * consoleName = "退室するときはEXITと打ってください。";
cout << consoleName;
Sleep(3000);
SetConsoleTitle(consoleName);
Sleep(50);
HWND hWnd = FindWindowA(NULL, consoleName);
if(hWnd){
HMENU hMenu = GetSystemMenu(hWnd, FALSE);
RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
SetConsoleCtrlHandler(NULL , TRUE);
}else{
// printf("%s\n", "失敗");
}
add_file(user + "さんが入室しました。");
while("EXIT"!=text){
if(text!=""){
if(!command(text)){
add_file(user+">>"+text);
}
}
display_file();
cerr << user << ">>";
history_reset();
getline(cin, text);
history_reset();
}
add_file(user + "さんが退室しました。");
return 0;
}
void add_file(string a){
if(a=="")return;
ofstream ofs(LOG_FILE,ios::binary|ios::app);
ofs << ango(a + "\r\n");
ofs.close();
}
void display_file(){
system("cls");
ifstream ifs(LOG_FILE,ios::binary);
if(!ifs){ return; } //ファイルが開けたか確認
char buf[256+1]; //256バイトと '\0 'の分のバッファ
while(!ifs.eof()){
ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
buf[ifs.gcount()] = '\0';
cout << ango(buf); //標準出力に出力してみる
}
ifs.close();
}
void history_reset(){/*
ここでAlt + F7 を押し自動で入力内容の
履歴を消すはずだが動作しないのでコメント化している。
ここの部分は検索中
知っている方は教えていただきたい
#define VK_MENU 0x12/*Alt*/
#define VK_F7 0x76/*F7*/
// キーの押し下げをシミュレートする。
keybd_event( VK_MENU, 0, 0, 0);
// キーの押し下げをシミュレートする。
keybd_event( VK_F7, 0, 0, 0);
system("timeout /t 1 /NOBREAK>nul");
// キーの解放をシミュレートする。
keybd_event( VK_F7, 0, KEYEVENTF_KEYUP, 0);
// キーの解放をシミュレートする。
keybd_event( VK_MENU, 0, KEYEVENTF_KEYUP, 0);*/
}
string ango(string tmp){
string ret=tmp;
for(int i = 0; i < (int)ret.size(); ++i){
ret[i] = ret[i] ^ KEY;
}
return ret;
}
//https://qiita.com/takahiro_itazuri/items/e999ae24ab34b2756b04
#include<string>
#include<fstream>
#include<iostream>
bool checkFileExistence(string str){
str=LOG_DIR"\\Users\\"+str;
ifstream ifs(str.c_str());
return ifs.is_open();
}
bool user_make(string userName){
if(checkFileExistence(userName)){
cout << userName << "は使用済みです。";
return false;
}
string str=LOG_DIR"\\Users\\"+userName;
ofstream ofs(str.c_str());
return true;
}
bool user_delete(string userName){
if(remove((LOG_DIR"\\Users\\"+userName).c_str()) != 0 ){
fprintf(stderr,"%sは存在しません",userName.c_str());
return false;
}
return true;
}
bool command(string text){
#define cmd_exec(x,y) {if(text.substr(0,strlen(x))==x){y(text.substr(strlen(x)));return true;}}
//x=string y=function
cmd_exec("/ban ",user_delete);
cmd_exec("/help ",help);
#undef cmd_exec
return false;
}
void help(string dummy){
cout
<< "/ban ユーザー名"
<< "ユーザーをtext.exeから追放します。"
<< "/help"
<< "この画面が表示されます。"
<< "EXIT"
<< "投稿を終了します。";
}