server.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: server.cpp
  3. // Purpose: Server for wxSocket demo
  4. // Author: Guillermo Rodriguez Garcia <guille@iies.es>
  5. // Created: 1999/09/19
  6. // Copyright: (c) 1999 Guillermo Rodriguez Garcia
  7. // (c) 2009 Vadim Zeitlin
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. // ==========================================================================
  11. // declarations
  12. // ==========================================================================
  13. // --------------------------------------------------------------------------
  14. // headers
  15. // --------------------------------------------------------------------------
  16. // For compilers that support precompilation, includes "wx/wx.h".
  17. #include "wx/wxprec.h"
  18. #ifdef __BORLANDC__
  19. # pragma hdrstop
  20. #endif
  21. // for all others, include the necessary headers
  22. #ifndef WX_PRECOMP
  23. # include "wx/wx.h"
  24. #endif
  25. #include "wx/busyinfo.h"
  26. #include "wx/socket.h"
  27. // this example is currently written to use only IP or only IPv6 sockets, it
  28. // should be extended to allow using either in the future
  29. #if wxUSE_IPV6
  30. typedef wxIPV6address IPaddress;
  31. #else
  32. typedef wxIPV4address IPaddress;
  33. #endif
  34. // --------------------------------------------------------------------------
  35. // resources
  36. // --------------------------------------------------------------------------
  37. // the application icon
  38. #ifndef wxHAS_IMAGES_IN_RESOURCES
  39. #include "../sample.xpm"
  40. #endif
  41. // --------------------------------------------------------------------------
  42. // classes
  43. // --------------------------------------------------------------------------
  44. // Define a new application type
  45. class MyApp : public wxApp
  46. {
  47. public:
  48. virtual bool OnInit();
  49. };
  50. // Define a new frame type: this is going to be our main frame
  51. class MyFrame : public wxFrame
  52. {
  53. public:
  54. MyFrame();
  55. ~MyFrame();
  56. // event handlers (these functions should _not_ be virtual)
  57. void OnUDPTest(wxCommandEvent& event);
  58. void OnWaitForAccept(wxCommandEvent& event);
  59. void OnQuit(wxCommandEvent& event);
  60. void OnAbout(wxCommandEvent& event);
  61. void OnServerEvent(wxSocketEvent& event);
  62. void OnSocketEvent(wxSocketEvent& event);
  63. void Test1(wxSocketBase *sock);
  64. void Test2(wxSocketBase *sock);
  65. void Test3(wxSocketBase *sock);
  66. // convenience functions
  67. void UpdateStatusBar();
  68. private:
  69. wxSocketServer *m_server;
  70. wxTextCtrl *m_text;
  71. wxMenu *m_menuFile;
  72. wxMenuBar *m_menuBar;
  73. bool m_busy;
  74. int m_numClients;
  75. // any class wishing to process wxWidgets events must use this macro
  76. wxDECLARE_EVENT_TABLE();
  77. };
  78. // simple helper class to log start and end of each test
  79. class TestLogger
  80. {
  81. public:
  82. TestLogger(const wxString& name) : m_name(name)
  83. {
  84. wxLogMessage("=== %s begins ===", m_name);
  85. }
  86. ~TestLogger()
  87. {
  88. wxLogMessage("=== %s ends ===", m_name);
  89. }
  90. private:
  91. const wxString m_name;
  92. };
  93. // --------------------------------------------------------------------------
  94. // constants
  95. // --------------------------------------------------------------------------
  96. // IDs for the controls and the menu commands
  97. enum
  98. {
  99. // menu items
  100. SERVER_UDPTEST = 10,
  101. SERVER_WAITFORACCEPT,
  102. SERVER_QUIT = wxID_EXIT,
  103. SERVER_ABOUT = wxID_ABOUT,
  104. // id for sockets
  105. SERVER_ID = 100,
  106. SOCKET_ID
  107. };
  108. // --------------------------------------------------------------------------
  109. // event tables and other macros for wxWidgets
  110. // --------------------------------------------------------------------------
  111. wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
  112. EVT_MENU(SERVER_QUIT, MyFrame::OnQuit)
  113. EVT_MENU(SERVER_ABOUT, MyFrame::OnAbout)
  114. EVT_MENU(SERVER_UDPTEST, MyFrame::OnUDPTest)
  115. EVT_MENU(SERVER_WAITFORACCEPT, MyFrame::OnWaitForAccept)
  116. EVT_SOCKET(SERVER_ID, MyFrame::OnServerEvent)
  117. EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
  118. wxEND_EVENT_TABLE()
  119. IMPLEMENT_APP(MyApp)
  120. // ==========================================================================
  121. // implementation
  122. // ==========================================================================
  123. // --------------------------------------------------------------------------
  124. // the application class
  125. // --------------------------------------------------------------------------
  126. bool MyApp::OnInit()
  127. {
  128. if ( !wxApp::OnInit() )
  129. return false;
  130. // Create the main application window
  131. MyFrame *frame = new MyFrame();
  132. // Show it
  133. frame->Show(true);
  134. // Success
  135. return true;
  136. }
  137. // --------------------------------------------------------------------------
  138. // main frame
  139. // --------------------------------------------------------------------------
  140. // frame constructor
  141. MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID_ANY,
  142. _("wxSocket demo: Server"),
  143. wxDefaultPosition, wxSize(300, 200))
  144. {
  145. // Give the frame an icon
  146. SetIcon(wxICON(sample));
  147. // Make menus
  148. m_menuFile = new wxMenu();
  149. m_menuFile->Append(SERVER_WAITFORACCEPT, "&Wait for connection\tCtrl-W");
  150. m_menuFile->Append(SERVER_UDPTEST, "&UDP test\tCtrl-U");
  151. m_menuFile->AppendSeparator();
  152. m_menuFile->Append(SERVER_ABOUT, _("&About\tCtrl-A"), _("Show about dialog"));
  153. m_menuFile->AppendSeparator();
  154. m_menuFile->Append(SERVER_QUIT, _("E&xit\tAlt-X"), _("Quit server"));
  155. // Append menus to the menubar
  156. m_menuBar = new wxMenuBar();
  157. m_menuBar->Append(m_menuFile, _("&File"));
  158. SetMenuBar(m_menuBar);
  159. #if wxUSE_STATUSBAR
  160. // Status bar
  161. CreateStatusBar(2);
  162. #endif // wxUSE_STATUSBAR
  163. // Make a textctrl for logging
  164. m_text = new wxTextCtrl(this, wxID_ANY,
  165. _("Welcome to wxSocket demo: Server\n"),
  166. wxDefaultPosition, wxDefaultSize,
  167. wxTE_MULTILINE | wxTE_READONLY);
  168. delete wxLog::SetActiveTarget(new wxLogTextCtrl(m_text));
  169. // Create the address - defaults to localhost:0 initially
  170. IPaddress addr;
  171. addr.Service(3000);
  172. wxLogMessage("Creating server at %s:%u", addr.IPAddress(), addr.Service());
  173. // Create the socket
  174. m_server = new wxSocketServer(addr);
  175. // We use IsOk() here to see if the server is really listening
  176. if (! m_server->IsOk())
  177. {
  178. wxLogMessage("Could not listen at the specified port !");
  179. return;
  180. }
  181. IPaddress addrReal;
  182. if ( !m_server->GetLocal(addrReal) )
  183. {
  184. wxLogMessage("ERROR: couldn't get the address we bound to");
  185. }
  186. else
  187. {
  188. wxLogMessage("Server listening at %s:%u",
  189. addrReal.IPAddress(), addrReal.Service());
  190. }
  191. // Setup the event handler and subscribe to connection events
  192. m_server->SetEventHandler(*this, SERVER_ID);
  193. m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
  194. m_server->Notify(true);
  195. m_busy = false;
  196. m_numClients = 0;
  197. UpdateStatusBar();
  198. }
  199. MyFrame::~MyFrame()
  200. {
  201. // No delayed deletion here, as the frame is dying anyway
  202. delete m_server;
  203. }
  204. // event handlers
  205. void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
  206. {
  207. // true is to force the frame to close
  208. Close(true);
  209. }
  210. void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
  211. {
  212. wxMessageBox(_("wxSocket demo: Server\n(c) 1999 Guillermo Rodriguez Garcia\n"),
  213. _("About Server"),
  214. wxOK | wxICON_INFORMATION, this);
  215. }
  216. void MyFrame::OnUDPTest(wxCommandEvent& WXUNUSED(event))
  217. {
  218. TestLogger logtest("UDP test");
  219. IPaddress addr;
  220. addr.Service(3000);
  221. wxDatagramSocket sock(addr);
  222. char buf[1024];
  223. size_t n = sock.RecvFrom(addr, buf, sizeof(buf)).LastCount();
  224. if ( !n )
  225. {
  226. wxLogMessage("ERROR: failed to receive data");
  227. return;
  228. }
  229. wxLogMessage("Received \"%s\" from %s:%u.",
  230. wxString::From8BitData(buf, n),
  231. addr.IPAddress(), addr.Service());
  232. for ( size_t i = 0; i < n; i++ )
  233. {
  234. char& c = buf[i];
  235. if ( (c >= 'A' && c <= 'M') || (c >= 'a' && c <= 'm') )
  236. c += 13;
  237. else if ( (c >= 'N' && c <= 'Z') || (c >= 'n' && c <= 'z') )
  238. c -= 13;
  239. }
  240. if ( sock.SendTo(addr, buf, n).LastCount() != n )
  241. {
  242. wxLogMessage("ERROR: failed to send data");
  243. return;
  244. }
  245. }
  246. void MyFrame::OnWaitForAccept(wxCommandEvent& WXUNUSED(event))
  247. {
  248. TestLogger logtest("WaitForAccept() test");
  249. wxBusyInfo("Waiting for connection for 10 seconds...", this);
  250. if ( m_server->WaitForAccept(10) )
  251. wxLogMessage("Accepted client connection.");
  252. else
  253. wxLogMessage("Connection error or timeout expired.");
  254. }
  255. void MyFrame::Test1(wxSocketBase *sock)
  256. {
  257. TestLogger logtest("Test 1");
  258. // Receive data from socket and send it back. We will first
  259. // get a byte with the buffer size, so we can specify the
  260. // exact size and use the wxSOCKET_WAITALL flag. Also, we
  261. // disabled input events so we won't have unwanted reentrance.
  262. // This way we can avoid the infamous wxSOCKET_BLOCK flag.
  263. sock->SetFlags(wxSOCKET_WAITALL);
  264. // Read the size
  265. unsigned char len;
  266. sock->Read(&len, 1);
  267. wxCharBuffer buf(len);
  268. // Read the data
  269. sock->Read(buf.data(), len);
  270. wxLogMessage("Got the data, sending it back");
  271. // Write it back
  272. sock->Write(buf, len);
  273. }
  274. void MyFrame::Test2(wxSocketBase *sock)
  275. {
  276. char buf[4096];
  277. TestLogger logtest("Test 2");
  278. // We don't need to set flags because ReadMsg and WriteMsg
  279. // are not affected by them anyway.
  280. // Read the message
  281. wxUint32 len = sock->ReadMsg(buf, sizeof(buf)).LastCount();
  282. if ( !len )
  283. {
  284. wxLogError("Failed to read message.");
  285. return;
  286. }
  287. wxLogMessage("Got \"%s\" from client.", wxString::FromUTF8(buf, len));
  288. wxLogMessage("Sending the data back");
  289. // Write it back
  290. sock->WriteMsg(buf, len);
  291. }
  292. void MyFrame::Test3(wxSocketBase *sock)
  293. {
  294. TestLogger logtest("Test 3");
  295. // This test is similar to the first one, but the len is
  296. // expressed in kbytes - this tests large data transfers.
  297. sock->SetFlags(wxSOCKET_WAITALL);
  298. // Read the size
  299. unsigned char len;
  300. sock->Read(&len, 1);
  301. wxCharBuffer buf(len*1024);
  302. // Read the data
  303. sock->Read(buf.data(), len * 1024);
  304. wxLogMessage("Got the data, sending it back");
  305. // Write it back
  306. sock->Write(buf, len * 1024);
  307. }
  308. void MyFrame::OnServerEvent(wxSocketEvent& event)
  309. {
  310. wxString s = _("OnServerEvent: ");
  311. wxSocketBase *sock;
  312. switch(event.GetSocketEvent())
  313. {
  314. case wxSOCKET_CONNECTION : s.Append(_("wxSOCKET_CONNECTION\n")); break;
  315. default : s.Append(_("Unexpected event !\n")); break;
  316. }
  317. m_text->AppendText(s);
  318. // Accept new connection if there is one in the pending
  319. // connections queue, else exit. We use Accept(false) for
  320. // non-blocking accept (although if we got here, there
  321. // should ALWAYS be a pending connection).
  322. sock = m_server->Accept(false);
  323. if (sock)
  324. {
  325. IPaddress addr;
  326. if ( !sock->GetPeer(addr) )
  327. {
  328. wxLogMessage("New connection from unknown client accepted.");
  329. }
  330. else
  331. {
  332. wxLogMessage("New client connection from %s:%u accepted",
  333. addr.IPAddress(), addr.Service());
  334. }
  335. }
  336. else
  337. {
  338. wxLogMessage("Error: couldn't accept a new connection");
  339. return;
  340. }
  341. sock->SetEventHandler(*this, SOCKET_ID);
  342. sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
  343. sock->Notify(true);
  344. m_numClients++;
  345. UpdateStatusBar();
  346. }
  347. void MyFrame::OnSocketEvent(wxSocketEvent& event)
  348. {
  349. wxString s = _("OnSocketEvent: ");
  350. wxSocketBase *sock = event.GetSocket();
  351. // First, print a message
  352. switch(event.GetSocketEvent())
  353. {
  354. case wxSOCKET_INPUT : s.Append(_("wxSOCKET_INPUT\n")); break;
  355. case wxSOCKET_LOST : s.Append(_("wxSOCKET_LOST\n")); break;
  356. default : s.Append(_("Unexpected event !\n")); break;
  357. }
  358. m_text->AppendText(s);
  359. // Now we process the event
  360. switch(event.GetSocketEvent())
  361. {
  362. case wxSOCKET_INPUT:
  363. {
  364. // We disable input events, so that the test doesn't trigger
  365. // wxSocketEvent again.
  366. sock->SetNotify(wxSOCKET_LOST_FLAG);
  367. // Which test are we going to run?
  368. unsigned char c;
  369. sock->Read(&c, 1);
  370. switch (c)
  371. {
  372. case 0xBE: Test1(sock); break;
  373. case 0xCE: Test2(sock); break;
  374. case 0xDE: Test3(sock); break;
  375. default:
  376. wxLogMessage("Unknown test id received from client");
  377. }
  378. // Enable input events again.
  379. sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
  380. break;
  381. }
  382. case wxSOCKET_LOST:
  383. {
  384. m_numClients--;
  385. // Destroy() should be used instead of delete wherever possible,
  386. // due to the fact that wxSocket uses 'delayed events' (see the
  387. // documentation for wxPostEvent) and we don't want an event to
  388. // arrive to the event handler (the frame, here) after the socket
  389. // has been deleted. Also, we might be doing some other thing with
  390. // the socket at the same time; for example, we might be in the
  391. // middle of a test or something. Destroy() takes care of all
  392. // this for us.
  393. wxLogMessage("Deleting socket.");
  394. sock->Destroy();
  395. break;
  396. }
  397. default: ;
  398. }
  399. UpdateStatusBar();
  400. }
  401. // convenience functions
  402. void MyFrame::UpdateStatusBar()
  403. {
  404. #if wxUSE_STATUSBAR
  405. wxString s;
  406. s.Printf(_("%d clients connected"), m_numClients);
  407. SetStatusText(s, 1);
  408. #endif // wxUSE_STATUSBAR
  409. }