diff --git a/CMakeLists.txt b/CMakeLists.txt index ad8302a..5cf8ed9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,7 @@ ${PROJECT_SOURCE_DIR}/src/ceSerial.cpp ${PROJECT_SOURCE_DIR}/src/ceWxTmr.cpp ${PROJECT_SOURCE_DIR}/src/ceUDP.cpp ${PROJECT_SOURCE_DIR}/src/ceTcpServer.cpp +${PROJECT_SOURCE_DIR}/src/ceTcpClient.cpp ${PROJECT_SOURCE_DIR}/src/ceMisc.cpp ${PROJECT_SOURCE_DIR}/src/ceFrame.cpp ${PROJECT_SOURCE_DIR}/src/ceFraChecksum.cpp diff --git a/examples/tcpclient/CMakeLists.txt b/examples/tcpclient/CMakeLists.txt new file mode 100644 index 0000000..de42d95 --- /dev/null +++ b/examples/tcpclient/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.15.0) +# directory name to be used as project name +project(tcpclient VERSION 1.0.1) +set(ADDCV NO) +# CMakeM1 checks ADDCV variable whether to include OpenCV +# and return LIBS variable with the list of libraries to link +# and also set WIN32OPT variable with WIN32 for Windows +include(${PROJECT_SOURCE_DIR}/../../CMakeM1.txt) +add_executable(${PROJECT_NAME} ${WIN32OPT} +${PROJECT_SOURCE_DIR}/src/${PROJECT_NAME}.cpp +) +target_link_libraries(${PROJECT_NAME} ${LIBS}) \ No newline at end of file diff --git a/examples/tcpclient/src/tcpclient.cpp b/examples/tcpclient/src/tcpclient.cpp new file mode 100644 index 0000000..fff76e3 --- /dev/null +++ b/examples/tcpclient/src/tcpclient.cpp @@ -0,0 +1,213 @@ +// File: tcpclient.cpp +// Description: A simple wxWidgets TCP client sample +// Author: Yan Naing Aye +// Web: http://cool-emerald.blogspot.com +// MIT License (https://opensource.org/licenses/MIT) +// Copyright (c) 2018 Yan Naing Aye + +// References +// [1] Guillermo Rodriguez Garcia, Vadim Zeitlin, "Server for wxSocket demo", +// https://github.com/wxWidgets/wxWidgets/blob/master/samples/sockets/server.cpp, 2009. +// [2] Julian Smart and Kevin Hock, "Cross-Platform GUI Programming with wxWidgets," +// Pearson Education, Inc. 2006. ISBN: 0-13-147381-6. + +#include "ce/ceUtil.h" +using namespace ce; +// IDs for the controls and the menu commands +enum +{ + ID_BTNSEND = 101, + ID_TXTSEND, + ID_TXTRX, + SOCKET_ID, + CLIENT_OPEN = wxID_OPEN, + CLIENT_CLOSE = wxID_CLOSE, + // menu items + Minimal_Quit = wxID_EXIT, + Minimal_About = wxID_ABOUT +}; + +class MyFrame; +class MyApp : public wxApp +{ + MyFrame *frame; +public: + ceTcpClient* _tcpclient; + void OnTcpSocketEvent(wxThreadEvent& event); + virtual bool OnInit(); +}; + +// Define a new frame type: this is going to be our main frame +class MyFrame : public wxFrame +{ +public: + // ctor(s) + MyFrame(MyApp* app, const wxString& title); + ~MyFrame(); + // event handlers (these functions should _not_ be virtual) + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void Print(std::string str); + void OnOpenConnection(wxCommandEvent& event); + void OnCloseConnection(wxCommandEvent& event); + void OnSend(wxCommandEvent& event); + void UpdateStatusBar(); +private: + MyApp* _app; + wxButton* btnSend; + wxTextCtrl* txtSend; + wxTextCtrl *txtRx; + wxMenu* fileMenu; + wxMenu* helpMenu; + // any class wishing to process wxWidgets events must use this macro + wxDECLARE_EVENT_TABLE(); +}; + +// event tables and other macros for wxWidgets +wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(Minimal_Quit, MyFrame::OnQuit) + EVT_MENU(Minimal_About, MyFrame::OnAbout) + EVT_MENU(CLIENT_OPEN, MyFrame::OnOpenConnection) + EVT_MENU(CLIENT_CLOSE, MyFrame::OnCloseConnection) +wxEND_EVENT_TABLE() + +IMPLEMENT_APP(MyApp) + +// 'Main program' equivalent: the program execution "starts" here +bool MyApp::OnInit() +{ + if ( !wxApp::OnInit() ) + return false; + + // depending on your system, some ports such as 3000, 8000, 8080 should be used with cautions + this->_tcpclient = new ceTcpClient(this,SOCKET_ID); + this->_tcpclient->SetRemote("localhost",7225); + Connect(SOCKET_ID, wxEVT_THREAD, wxThreadEventHandler(MyApp::OnTcpSocketEvent)); + frame = new MyFrame(this,"TCP Client using ceUtil lib"); + frame->Show(true); + this->frame->Print("Click Open Session menu to start a connection"); + return true; +} + +void MyApp::OnTcpSocketEvent(wxThreadEvent& event) +{ + std::vector v = event.GetPayload>(); + std::string s = event.GetString().ToStdString(); + int i = event.GetInt(); + std::string str = "Socket event: Rx vec = "+ceMisc::cvec2hex(v)+", ip ="+s+", port = "+ std::to_string(i); + printf("%s\n",str.c_str()); + this->frame->Print(str); +} + +// frame constructor +MyFrame::MyFrame(MyApp* app, const wxString& title) +: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(390, 280), + wxDEFAULT_FRAME_STYLE ^ wxRESIZE_BORDER),_app(app) +{ +#if wxUSE_MENUS +// create a menu bar +wxMenu *fileMenu = new wxMenu; + +// the "About" item should be in the help menu +wxMenu *helpMenu = new wxMenu; +helpMenu->Append(Minimal_About, "&About\tF1", "Show about dialog"); + +fileMenu->Append(CLIENT_OPEN, "&Open session\tAlt-O", "Connect to server"); +fileMenu->Append(CLIENT_CLOSE, "&Close session\tAlt-C", "Close connection"); +fileMenu->Append(Minimal_Quit, "E&xit\tAlt-X", "Quit this program"); + +// now append the freshly created menu to the menu bar... +wxMenuBar *menuBar = new wxMenuBar(); +menuBar->Append(fileMenu, "&File"); +menuBar->Append(helpMenu, "&Help"); + +// ... and attach this menu bar to the frame +SetMenuBar(menuBar); +#endif // wxUSE_MENUS + +#if wxUSE_STATUSBAR +// create a status bar just for fun (by default with 1 pane only) +CreateStatusBar(2); +SetStatusText("TCP client using ceUtil lib"); +#endif // wxUSE_STATUSBAR +btnSend = new wxButton(this, ID_BTNSEND, wxT("Send"), + wxPoint(5, 5), wxSize(100, 25)); +txtSend = new wxTextCtrl(this, ID_TXTSEND, wxT("Hello!"), + wxPoint(120, 5), wxSize(250, 25)); +txtRx = new wxTextCtrl(this, ID_TXTRX, wxT(""), + wxPoint(5, 35), wxSize(365, 125), wxTE_MULTILINE); + +Connect(ID_BTNSEND, wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler(MyFrame::OnSend)); +} + +MyFrame::~MyFrame() +{ + // No delayed deletion here, as the frame is dying anyway +} + +// event handlers +void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ +// true is to force the frame to close +Close(true); +} + +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ +wxMessageBox(wxString::Format +( +"ceUtil TCP client sample\n" +"\n" +"Author: Yan Naing Aye \n" +"Web: http://cool-emerald.blogspot.com" +), +"About ceUtil TCP client sample", +wxOK | wxICON_INFORMATION, +this); +} + +void MyFrame::Print(std::string str) +{ + txtRx->AppendText(wxString::Format(wxT("%s\n"),str)); +} + +void MyFrame::UpdateStatusBar() +{ + //fileMenu->Enable(CLIENT_OPEN, !_app->_tcpclient->IsConnected()); + //fileMenu->Enable(CLIENT_CLOSE, _app->_tcpclient->IsConnected()); + //if (_app->_tcpclient->IsConnected()) { + // //SetStatusText(wxString::Format(wxT("%s:%u"), + // // addr.IPAddress(), addr.Service()), 1); + // SetStatusText(wxString::Format(wxT("Connected")), 1); + //} + //else { + // SetStatusText(wxString::Format(wxT("Not connected")), 1); + //} +} + +void MyFrame::OnOpenConnection(wxCommandEvent& WXUNUSED(event)) +{ + _app->_tcpclient->Open(); + // fileMenu->Enable(CLIENT_OPEN, false); + // fileMenu->Enable(CLIENT_CLOSE, false); + //update status + this->UpdateStatusBar(); +} + +void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event)) +{ + _app->_tcpclient->Close(); + + //update status + this->UpdateStatusBar(); +} + +void MyFrame::OnSend(wxCommandEvent& WXUNUSED(event)) +{ + wxString str = txtSend->GetValue(); + wxCharBuffer buffer = str.ToUTF8(); + size_t txn = buffer.length();//for non-ASCII chars, having more than one byte per char + std::vector vc{buffer.data(), buffer.data()+txn}; + _app->_tcpclient->Tx(vc); +} \ No newline at end of file diff --git a/examples/tcpclient/tcpclient.sh b/examples/tcpclient/tcpclient.sh new file mode 100644 index 0000000..6979d63 --- /dev/null +++ b/examples/tcpclient/tcpclient.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +SCRIPTNAME=`basename "$0"` +PRJNAME="${SCRIPTNAME%.*}" +SCRIPTDIR="${0%/$PRJNAME.*}" +echo "Project: $PRJNAME" +echo "Script directory: $SCRIPTDIR" + +if [ $# == 1 ]; then + opt_sh=$1 +else + echo "You can input argument:" + echo " 'cmake' : to generate cmake files, build, and install" + echo " 'build': to build and run" + echo " ..." + read -p "Input an option: " opt_sh +fi + +if [[ "$opt_sh" == "" ]]; then + opt_sh="build" +fi + +echo "Option: $opt_sh" +echo " ." +echo " ." +echo " ." + +cd $SCRIPTDIR +if [[ "$opt_sh" == "cmake" ]]; then + echo "Preparing cmake file" + if [[ ! -d "./build" ]]; then + mkdir -p build + fi + rm -r ./build/* + cd build + cmake -D CMAKE_BUILD_TYPE=Release \ + -D CMAKE_INSTALL_PREFIX=/usr/local \ + .. + cd .. + echo " ." + echo " ." + echo " ." +fi + +if [[ $opt_sh == "cmake" ]] || [[ $opt_sh == "build" ]]; then + echo "Building ..." + cd $SCRIPTDIR/build && make # && sudo make install + if [[ $? == 0 ]]; then + echo "Build successful" + echo "Running ..." + ./$PRJNAME + else + echo "Error in compiling" + fi +else + echo "Running ..." + ./$PRJNAME +fi + + diff --git a/examples/tcpclient/tcpclient/tcpclient.sln b/examples/tcpclient/tcpclient/tcpclient.sln new file mode 100644 index 0000000..8955428 --- /dev/null +++ b/examples/tcpclient/tcpclient/tcpclient.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcpclient", "tcpclient.vcxproj", "{9E6EFA9E-8164-4807-B820-F97C9CFBFED1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Debug|x64.ActiveCfg = Debug|x64 + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Debug|x64.Build.0 = Debug|x64 + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Debug|x86.ActiveCfg = Debug|Win32 + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Debug|x86.Build.0 = Debug|Win32 + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Release|x64.ActiveCfg = Release|x64 + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Release|x64.Build.0 = Release|x64 + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Release|x86.ActiveCfg = Release|Win32 + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D0A51A18-2F03-4C7F-9C10-DB3BA0B948C1} + EndGlobalSection +EndGlobal diff --git a/examples/tcpclient/tcpclient/tcpclient.vcxproj b/examples/tcpclient/tcpclient/tcpclient.vcxproj new file mode 100644 index 0000000..52e2417 --- /dev/null +++ b/examples/tcpclient/tcpclient/tcpclient.vcxproj @@ -0,0 +1,165 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 16.0 + {9E6EFA9E-8164-4807-B820-F97C9CFBFED1} + Win32Proj + tcpclient + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + NotSet + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + true + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + + + Level3 + Disabled + true + _DEBUG;_WINDOWS;%(PreprocessorDefinitions);WXUSINGDLL;_CRT_SECURE_NO_WARNINGS + true + $(VCPKG_ROOT)\installed\include; + + + Windows + true + $(VCPKG_ROOT)\installed\$(Platform)-windows\lib + $(CoreLibraryDependencies);%(AdditionalDependencies);ceutild.lib + + + + + + + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + + + Level3 + MaxSpeed + true + true + true + NDEBUG;_WINDOWS;WXUSINGDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + $(SolutionDir)..\..\..\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + $(SolutionDir)..\..\..\ceUtil\x64\Release;%(AdditionalLibraryDirectories) + ceUtil.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/examples/tcpclient/tcpclientw.bat b/examples/tcpclient/tcpclientw.bat new file mode 100644 index 0000000..3141271 --- /dev/null +++ b/examples/tcpclient/tcpclientw.bat @@ -0,0 +1,11 @@ +@REM To run the script set VCPKGDIR environmental variable for vcpkg root folder +if exist ./buildw/ ( +rmdir /s /q ./buildw +) +cmake -B ./buildw -S ./ -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake" -D CMAKE_INSTALL_PREFIX=./installed/ &&^ +cmake --build ./buildw --config Release +@REM cmake --install ./buildw --config Release +cd buildw/Release +tcpclient.exe +@REM cpack --verbose +@REM cd ../.. diff --git a/examples/tcpclient/vscode/settings.json b/examples/tcpclient/vscode/settings.json new file mode 100644 index 0000000..7df3b83 --- /dev/null +++ b/examples/tcpclient/vscode/settings.json @@ -0,0 +1,10 @@ +{ + "files.associations": { + "*.tcc": "cpp", + "fstream": "cpp", + "sstream": "cpp" + }, + "cmake.configureSettings": { + "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + } +} \ No newline at end of file diff --git a/examples/tcpsvr/src/myicon.xpm b/examples/tcpsvr/src/myicon.xpm deleted file mode 100644 index e8def82..0000000 --- a/examples/tcpsvr/src/myicon.xpm +++ /dev/null @@ -1,118 +0,0 @@ -/* XPM */ -static char const* sample_xpm[] = { -"64 64 51 1", -" c None", -". c #008000", -"+ c #007F00", -"@ c #007900", -"# c #007D00", -"$ c #6BB56B", -"% c #FDFEFD", -"& c #54AA54", -"* c #FFFFFF", -"= c #007A00", -"- c #F0F7F0", -"; c #309830", -"> c #2F982F", -", c #69B469", -"' c #68B468", -") c #7EBF7E", -"! c #80C080", -"~ c #018001", -"{ c #0B850B", -"] c #72B872", -"^ c #7CBE7C", -"/ c #3A9D3A", -"( c #71B871", -"_ c #FEFEFE", -": c #E4F2E4", -"< c #359A35", -"[ c #007E00", -"} c #E5F2E5", -"| c #68B368", -"1 c #6FB76F", -"2 c #7BBD7B", -"3 c #399D39", -"4 c #349A34", -"5 c #70B870", -"6 c #67B367", -"7 c #6DB66D", -"8 c #71B971", -"9 c #79BC79", -"0 c #D8EBD8", -"a c #D7EBD7", -"b c #7ABD7A", -"c c #D5EAD5", -"d c #D6EBD6", -"e c #55AA55", -"f c #6AB56A", -"g c #FCFEFC", -"h c #6AB46A", -"i c #53A953", -"j c #2F972F", -"k c #6EB76E", -"l c #7DBF7D", -" ................................................ ", -" ...................................................... ", -" ........................................................ ", -" ...........................+@@+........................... ", -" ...........................#$%%$#........................... ", -" ............................&****&............................ ", -" ...........................=-****-=........................... ", -" ...........................;******>........................... ", -"............................,******'............................", -"............................)******)............................", -"............................!******!............................", -"...........~{]^/=...........!******!...........=/^({~...........", -"...........{_***:<[.........!******!.........[<}***_{...........", -"...........(******|#........!******!........#'******(...........", -"...........^*******(#.......!******!.......#1*******2...........", -".........../********(#......!******!......#1********3...........", -"...........=:********(#.....!******!.....#1********:=...........", -"............4*********5#....!******!....#1*********<............", -"............[6*********(#...!******!...#1*********'[............", -".............#7*********8#..!******!..#1*********1#.............", -"..............#7*********8#.!******!.#1*********1#..............", -"...............#7*********8#!******!#1*********1#...............", -"................#7*********89******91*********1#................", -".................#7*********0******a*********1#.................", -"..................#7************************1#..................", -"...................#7**********************1#...................", -"....................#7********************1#....................", -".....................#7******************1#.....................", -"......=;,)!!!!!!!!!!!!bc****************d9!!!!!!!!!!!!),;=......", -"....#e-**************************************************-&#....", -"...+$******************************************************f+...", -"...@%******************************************************%@...", -"...@%******************************************************g@...", -"...+f******************************************************h+...", -"....#&-**************************************************-i#....", -"......=>')!!!!!!!!!!!!9a****************09!!!!!!!!!!!!)'j=......", -".....................#1******************8#.....................", -"....................#1********************8#....................", -"...................#1**********************8#...................", -"..................#1************************8#..................", -".................#1*********d******c*********8#.................", -"................#1*********19******b7*********8#................", -"...............#1*********1#!******!#7*********8#...............", -"..............#1*********1#.!******!.#7*********8#..............", -".............#1*********1#..!******!..#7*********8#.............", -"............[|*********1#...!******!...#7*********,[............", -"............4*********1#....!******!....#k*********<............", -"...........=}********1#.....!******!.....#k********}=...........", -".........../********1#......!******!......#k********/...........", -"...........^*******1#.......!******!.......#k*******2...........", -"...........(******|#........!******!........#6******5...........", -"...........{_***:4[.........!******!.........[<:***_{...........", -"...........~{523=...........!******!...........=32({~...........", -"............................!******!............................", -"............................)******l............................", -"............................,******'............................", -" ...........................;******j........................... ", -" ...........................=-****-=........................... ", -" ............................&****&............................ ", -" ...........................#f%gh#........................... ", -" ...........................+@@+........................... ", -" ........................................................ ", -" ...................................................... ", -" ................................................ "}; diff --git a/examples/tcpsvr/src/tcpsvr.cpp b/examples/tcpsvr/src/tcpsvr.cpp index 5e0fa33..56b0471 100644 --- a/examples/tcpsvr/src/tcpsvr.cpp +++ b/examples/tcpsvr/src/tcpsvr.cpp @@ -12,7 +12,7 @@ // Pearson Education, Inc. 2006. ISBN: 0-13-147381-6. #include "ce/ceUtil.h" -#include "myicon.xpm" +// #include "myicon.xpm" using namespace ce; // IDs for the controls and the menu commands enum @@ -108,8 +108,8 @@ MyFrame::MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(390, 280), wxDEFAULT_FRAME_STYLE ^ wxRESIZE_BORDER) { -// set the frame icon -SetIcon(wxICON(sample)); +// // set the frame icon +// SetIcon(wxICON(sample)); #if wxUSE_MENUS // create a menu bar diff --git a/examples/tcpsvr/tcpsvr/tcpsvr.sln b/examples/tcpsvr/tcpsvr/tcpsvr.sln index 07990ff..4967f48 100644 --- a/examples/tcpsvr/tcpsvr/tcpsvr.sln +++ b/examples/tcpsvr/tcpsvr/tcpsvr.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 17.8.34330.188 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcpsvr", "tcpsvr.vcxproj", "{9E6EFA9E-8164-4807-B820-F97C9CFBFED1}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ceutil", "..\..\..\vcprj\ceutil.vcxproj", "{5397B256-872B-44E9-A100-8EE02B070E5A}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -23,14 +21,6 @@ Global {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Release|x64.Build.0 = Release|x64 {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Release|x86.ActiveCfg = Release|Win32 {9E6EFA9E-8164-4807-B820-F97C9CFBFED1}.Release|x86.Build.0 = Release|Win32 - {5397B256-872B-44E9-A100-8EE02B070E5A}.Debug|x64.ActiveCfg = Debug|x64 - {5397B256-872B-44E9-A100-8EE02B070E5A}.Debug|x64.Build.0 = Debug|x64 - {5397B256-872B-44E9-A100-8EE02B070E5A}.Debug|x86.ActiveCfg = Debug|Win32 - {5397B256-872B-44E9-A100-8EE02B070E5A}.Debug|x86.Build.0 = Debug|Win32 - {5397B256-872B-44E9-A100-8EE02B070E5A}.Release|x64.ActiveCfg = Release|x64 - {5397B256-872B-44E9-A100-8EE02B070E5A}.Release|x64.Build.0 = Release|x64 - {5397B256-872B-44E9-A100-8EE02B070E5A}.Release|x86.ActiveCfg = Release|Win32 - {5397B256-872B-44E9-A100-8EE02B070E5A}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/examples/tcpsvr/vscode/settings.json b/examples/tcpsvr/vscode/settings.json new file mode 100644 index 0000000..7df3b83 --- /dev/null +++ b/examples/tcpsvr/vscode/settings.json @@ -0,0 +1,10 @@ +{ + "files.associations": { + "*.tcc": "cpp", + "fstream": "cpp", + "sstream": "cpp" + }, + "cmake.configureSettings": { + "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + } +} \ No newline at end of file diff --git a/include/ce/ceTcpClient.h b/include/ce/ceTcpClient.h new file mode 100644 index 0000000..dd2e8ca --- /dev/null +++ b/include/ce/ceTcpClient.h @@ -0,0 +1,55 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: ceTcpClient.h +// Description: TCP client module +// Author: Yan Naing Aye +// Ref: http://cool-emerald.blogspot.com/2018/01/udptcp-socket-programming-with-wxwidgets.html +///////////////////////////////////////////////////////////////////////////// + +#ifndef CETCPCLIENT_H +#define CETCPCLIENT_H +#include "ce/ceMacros.h" // macros +#if CE_WX==1 +#include +#include +#include +#include "wx/wx.h" +#include "wx/socket.h" +#include "ce/ceMisc.h" // utilities +// this example is currently written to use only IP or only IPv4 sockets, it +// should be extended to allow using either in the future +//#if wxUSE_IPV6 +//typedef wxIPV6address IPaddress; +//#else +typedef wxIPV4address IPaddress; +//#endif +#define CE_TCPCLIENT_RX_BUF_SIZE 32768 + +namespace ce { +class ceTcpClient : public wxEvtHandler { +public: + ceTcpClient(wxAppConsole* app, int socketid); // port = listening port number + ~ceTcpClient(); + + void Open(); + void Close(); + + // Transmit (write) + int Tx(std::vector bv); // return 0 = success, 1 = error + // Receive (read) will raise receive event + + void SetRemote(std::string remotehost, int port); + bool IsConnected(); + bool IsOK(); +private: + void OnSocketEvent(wxSocketEvent& event); + wxAppConsole* _app; + int _socket_id; + int _port{ 0 }; + std::string _remotehost{""}; + wxSocketClient* _socketClient{}; + void PrintLog(std::string str); +}; + +} // namespace ce +#endif // CE_WX +#endif // CETCPCLIENT_H diff --git a/include/ce/ceTcpServer.h b/include/ce/ceTcpServer.h index 470f1fb..2ec22d5 100644 --- a/include/ce/ceTcpServer.h +++ b/include/ce/ceTcpServer.h @@ -44,8 +44,6 @@ class ceTcpServer : public wxEvtHandler { int _server_id; int _port; bool _listening{false}; - std::string _remote_host{""}; - int _remote_port{0}; wxSocketServer* _socketServer{}; wxSocketBase* _socketBase{}; void PrintLog(std::string str); diff --git a/include/ce/ceUtil.h b/include/ce/ceUtil.h index 8fc615b..bdf5576 100644 --- a/include/ce/ceUtil.h +++ b/include/ce/ceUtil.h @@ -31,6 +31,7 @@ // tcp #include "ce/ceTcpServer.h" +#include "ce/ceTcpClient.h" // utilities #include "ce/ceMisc.h" diff --git a/src/ceTcpClient.cpp b/src/ceTcpClient.cpp new file mode 100644 index 0000000..eaec5f0 --- /dev/null +++ b/src/ceTcpClient.cpp @@ -0,0 +1,165 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: ceTcpClient.cpp +// Description: TCP client module +// Author: Yan Naing Aye +// Ref: http://cool-emerald.blogspot.com/2018/01/udptcp-socket-programming-with-wxwidgets.html +///////////////////////////////////////////////////////////////////////////// +#include +#include "ce/ceTcpClient.h" +using namespace std; + +#if CE_WX==1 +namespace ce { + +void ceTcpClient::PrintLog(string str) +{ + // printf("%s \n",str.c_str()); +} + +ceTcpClient::ceTcpClient(wxAppConsole* app, int socketid): +_app(app),_socket_id(socketid) +{ + // Create the socket + this->_socketClient = new wxSocketClient(); + // Setup the event handler and subscribe to most events + _socketClient->SetEventHandler(*this, _socket_id); + _socketClient->SetNotify(wxSOCKET_CONNECTION_FLAG | + wxSOCKET_INPUT_FLAG | + wxSOCKET_LOST_FLAG); + _socketClient->Notify(true); + Connect(_socket_id, wxEVT_SOCKET, wxSocketEventHandler(ceTcpClient::OnSocketEvent)); +} + +ceTcpClient::~ceTcpClient() +{ + this->Close(); + Disconnect(_socket_id, wxEVT_SOCKET); + _socketClient->Destroy(); +} + +void ceTcpClient::SetRemote(string remotehost, int port) +{ + _remotehost = remotehost; + _port = port; +} + +void ceTcpClient::Open() +{ + // Create the address + IPaddress addr; + //addr.AnyAddress(); + addr.Hostname(_remotehost); + addr.Service(_port); + PrintLog("Trying to connect to " + addr.IPAddress().ToStdString() + + ":" + to_string(addr.Service())); + + // we connect asynchronously and will get a wxSOCKET_CONNECTION event when + // the connection is really established + // + // if you want to make sure that connection is established right here you + // could call WaitOnConnect(timeout) instead + + _socketClient->Connect(addr, false); +} + +void ceTcpClient::Close() +{ + _socketClient->Close(); +} + +void ceTcpClient::OnSocketEvent(wxSocketEvent& event) +{ + PrintLog("OnSocketEvent"); + wxSocketBase *sockBase = event.GetSocket(); + std::vector vc; + char buf[CE_TCPCLIENT_RX_BUF_SIZE]; + + // First, print a message + switch (event.GetSocketEvent()) + { + case wxSOCKET_INPUT: + this->PrintLog("wxSOCKET_INPUT"); + break; + case wxSOCKET_LOST: + this->PrintLog("wxSOCKET_LOST"); + break; + case wxSOCKET_CONNECTION: + this->PrintLog("wxSOCKET_CONNECTION"); + break; + default: + this->PrintLog("Unexpected event"); + break; + } + + // Now we process the event + switch (event.GetSocketEvent()) + { + case wxSOCKET_INPUT: + { + // We disable input events, so that the test doesn't trigger + // wxSocketEvent again. + sockBase->SetNotify(wxSOCKET_LOST_FLAG); + + // Receive data from socket and send it back. We will first + // get a byte with the buffer size, so we can specify the + // exact size and use the wxSOCKET_WAITALL flag. Also, we + // disabled input events so we won't have unwanted reentrance. + // This way we can avoid the infamous wxSOCKET_BLOCK flag. + // sockBase->SetFlags(wxSOCKET_WAITALL); + + // Read the message + size_t lenRd = sockBase->Read(buf, sizeof(buf)).LastCount(); + if (!lenRd) { + PrintLog("Failed to read message"); + return; + } + else { + PrintLog("Read " + to_string(lenRd) + " bytes"); + // string str(buf,lenRd); + // PrintLog("Rx: " + str) + } + // Enable input events again. + sockBase->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG); + vc.assign(buf, buf + lenRd); + wxThreadEvent eventskt(wxEVT_THREAD, _socket_id); + eventskt.SetPayload>(vc); + eventskt.SetString(_remotehost); + eventskt.SetInt(_port); + wxQueueEvent(_app, eventskt.Clone()); + break; + } + default: + break; + } +} + +int ceTcpClient::Tx(std::vector bv) +{ + size_t txn = 0; + if (this->_socketClient->IsOk() && this->_socketClient->IsConnected()) { + // Write to pointed client + txn = bv.size(); + size_t n = _socketClient->Write(bv.data(), txn).LastCount(); + if ( n!= txn) { + perror("ceTcpClient write error"); + txn = n; + } + else { + PrintLog("Tx: " + ceMisc::cvec2hex(bv)); + } + } + return int(txn); +} + +bool ceTcpClient::IsConnected() +{ + return this->_socketClient->IsConnected(); +} + +bool ceTcpClient::IsOK() +{ + return this->_socketClient->IsOk(); +} + +} // namespace ce +#endif // CE_WX \ No newline at end of file diff --git a/src/ceTcpServer.cpp b/src/ceTcpServer.cpp index f2d24b8..2067719 100644 --- a/src/ceTcpServer.cpp +++ b/src/ceTcpServer.cpp @@ -251,8 +251,14 @@ int ceTcpServer::Tx(std::vector bv) if(this->_socketBase->IsOk() && this->_socketBase->IsConnected()) { // Write to pointed client txn = bv.size(); - _socketBase->Write(bv.data(), txn); - PrintLog("Tx: " + ceMisc::cvec2hex(bv)); + size_t n = _socketBase->Write(bv.data(), txn).LastCount(); + if (n != txn) { + perror("ceTcpClient write error"); + txn = n; + } + else { + PrintLog("Tx: " + ceMisc::cvec2hex(bv)); + } } } return int(txn); diff --git a/vcprj/ceutil.vcxproj b/vcprj/ceutil.vcxproj index 7797466..9d9d043 100644 --- a/vcprj/ceutil.vcxproj +++ b/vcprj/ceutil.vcxproj @@ -35,6 +35,7 @@ + @@ -58,6 +59,7 @@ + diff --git a/vcprj/ceutil.vcxproj.filters b/vcprj/ceutil.vcxproj.filters index 51e9afc..445c617 100644 --- a/vcprj/ceutil.vcxproj.filters +++ b/vcprj/ceutil.vcxproj.filters @@ -81,6 +81,9 @@ Header Files + + Header Files + @@ -143,5 +146,8 @@ Source Files + + Source Files + \ No newline at end of file