]>
git.saurik.com Git - wxWidgets.git/blob - samples/sockets/client.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Client for wxSocket demo
4 // Author: Guillermo Rodriguez Garcia <guille@iies.es>
8 // Copyright: (c) 1999 Guillermo Rodriguez Garcia
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ==========================================================================
14 // ==========================================================================
16 // --------------------------------------------------------------------------
18 // --------------------------------------------------------------------------
21 # pragma implementation "client.cpp"
22 # pragma interface "client.cpp"
25 // For compilers that support precompilation, includes "wx/wx.h".
26 #include "wx/wxprec.h"
32 // for all others, include the necessary headers
37 #include "wx/socket.h"
39 #include "wx/wfstream.h"
41 // --------------------------------------------------------------------------
43 // --------------------------------------------------------------------------
45 // the application icon
46 #if defined(__WXGTK__) || defined(__WXMOTIF__)
47 # include "mondrian.xpm"
50 // --------------------------------------------------------------------------
52 // --------------------------------------------------------------------------
54 // Define a new application type
55 class MyApp
: public wxApp
58 virtual bool OnInit();
61 // Define a new frame type: this is going to be our main frame
62 class MyFrame
: public wxFrame
68 // event handlers for File menu
69 void OnQuit(wxCommandEvent
& event
);
70 void OnAbout(wxCommandEvent
& event
);
72 // event handlers for Socket menu
73 void OnOpenConnection(wxCommandEvent
& event
);
74 void OnTest1(wxCommandEvent
& event
);
75 void OnTest2(wxCommandEvent
& event
);
76 void OnTest3(wxCommandEvent
& event
);
77 void OnCloseConnection(wxCommandEvent
& event
);
79 // event handlers for Protocols menu
80 void OnTestURL(wxCommandEvent
& event
);
82 // event handlers for DatagramSocket menu
83 void OnDatagram(wxCommandEvent
& event
);
85 // socket event handler
86 void OnSocketEvent(wxSocketEvent
& event
);
88 // convenience functions
89 void UpdateStatusBar();
92 wxSocketClient
*m_sock
;
97 wxMenu
*m_menuDatagramSocket
;
98 wxMenu
*m_menuProtocols
;
102 // any class wishing to process wxWindows events must use this macro
103 DECLARE_EVENT_TABLE()
106 // --------------------------------------------------------------------------
108 // --------------------------------------------------------------------------
110 // IDs for the controls and the menu commands
128 // --------------------------------------------------------------------------
129 // event tables and other macros for wxWindows
130 // --------------------------------------------------------------------------
132 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
133 EVT_MENU(CLIENT_QUIT
, MyFrame::OnQuit
)
134 EVT_MENU(CLIENT_ABOUT
, MyFrame::OnAbout
)
135 EVT_MENU(CLIENT_OPEN
, MyFrame::OnOpenConnection
)
136 EVT_MENU(CLIENT_TEST1
, MyFrame::OnTest1
)
137 EVT_MENU(CLIENT_TEST2
, MyFrame::OnTest2
)
138 EVT_MENU(CLIENT_TEST3
, MyFrame::OnTest3
)
139 EVT_MENU(CLIENT_CLOSE
, MyFrame::OnCloseConnection
)
140 EVT_MENU(CLIENT_DGRAM
, MyFrame::OnDatagram
)
141 EVT_MENU(CLIENT_TESTURL
, MyFrame::OnTestURL
)
142 EVT_SOCKET(SOCKET_ID
, MyFrame::OnSocketEvent
)
147 // ==========================================================================
149 // ==========================================================================
151 // --------------------------------------------------------------------------
152 // the application class
153 // --------------------------------------------------------------------------
157 // Create the main application window
158 MyFrame
*frame
= new MyFrame();
160 // Show it and tell the application that it's our main window
168 // --------------------------------------------------------------------------
170 // --------------------------------------------------------------------------
173 MyFrame::MyFrame() : wxFrame((wxFrame
*)NULL
, -1,
174 _("wxSocket demo: Client"),
175 wxDefaultPosition
, wxSize(300, 200))
177 // Give the frame an icon
178 SetIcon(wxICON(mondrian
));
181 m_menuFile
= new wxMenu();
182 m_menuFile
->Append(CLIENT_ABOUT
, _("&About...\tCtrl-A"), _("Show about dialog"));
183 m_menuFile
->AppendSeparator();
184 m_menuFile
->Append(CLIENT_QUIT
, _("E&xit\tAlt-X"), _("Quit client"));
186 m_menuSocket
= new wxMenu();
187 m_menuSocket
->Append(CLIENT_OPEN
, _("&Open session"), _("Connect to server"));
188 m_menuSocket
->AppendSeparator();
189 m_menuSocket
->Append(CLIENT_TEST1
, _("Test &1"), _("Test basic functionality"));
190 m_menuSocket
->Append(CLIENT_TEST2
, _("Test &2"), _("Test ReadMsg and WriteMsg"));
191 m_menuSocket
->Append(CLIENT_TEST3
, _("Test &3"), _("Test large data transfer"));
192 m_menuSocket
->AppendSeparator();
193 m_menuSocket
->Append(CLIENT_CLOSE
, _("&Close session"), _("Close connection"));
195 m_menuDatagramSocket
= new wxMenu();
196 m_menuDatagramSocket
->Append(CLIENT_DGRAM
, _("Send Datagram"), _("Test UDP sockets"));
198 m_menuProtocols
= new wxMenu();
199 m_menuProtocols
->Append(CLIENT_TESTURL
, _("Test URL"), _("Get data from the specified URL"));
201 // Append menus to the menubar
202 m_menuBar
= new wxMenuBar();
203 m_menuBar
->Append(m_menuFile
, _("&File"));
204 m_menuBar
->Append(m_menuSocket
, _("&SocketClient"));
205 m_menuBar
->Append(m_menuDatagramSocket
, _("&DatagramSocket"));
206 m_menuBar
->Append(m_menuProtocols
, _("&Protocols"));
207 SetMenuBar(m_menuBar
);
212 // Make a panel with a textctrl in it
213 m_panel
= new wxPanel(this, -1, wxPoint(0, 0), GetClientSize());
214 m_text
= new wxTextCtrl(m_panel
, -1,
215 _("Welcome to wxSocket demo: Client\n"
217 wxPoint(0, 0), m_panel
->GetClientSize(),
218 wxTE_MULTILINE
| wxTE_READONLY
);
221 m_sock
= new wxSocketClient();
222 m_sock
->SetEventHandler(*this, SOCKET_ID
);
223 m_sock
->SetNotify(wxSOCKET_CONNECTION_FLAG
|
224 wxSOCKET_INPUT_FLAG
|
226 m_sock
->Notify(TRUE
);
239 void MyFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
241 // TRUE is to force the frame to close
245 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
247 wxMessageBox(_("wxSocket demo: Client\n"
248 "(c) 1999 Guillermo Rodriguez Garcia\n"),
250 wxOK
| wxICON_INFORMATION
, this);
253 void MyFrame::OnOpenConnection(wxCommandEvent
& WXUNUSED(event
))
257 m_menuSocket
->Enable(CLIENT_OPEN
, FALSE
);
258 m_menuSocket
->Enable(CLIENT_CLOSE
, FALSE
);
260 // Ask user for server address
261 wxString hostname
= wxGetTextFromUser(
262 _("Enter the address of the wxSocket demo server:"),
266 addr
.Hostname(hostname
);
269 // Mini-tutorial for Connect() :-)
270 // ---------------------------
272 // There are two ways to use Connect(): blocking and non-blocking,
273 // depending on the value passed as the 'wait' (2nd) parameter.
275 // Connect(addr, TRUE) will wait until the connection completes,
276 // returning TRUE on success and FALSE on failure. This call blocks
277 // the GUI (this might be changed in future releases to honour the
278 // wxSOCKET_BLOCK flag).
280 // Connect(addr, FALSE) will issue a nonblocking connection request
281 // and return immediately. If the return value is TRUE, then the
282 // connection has been already succesfully established. If it is
283 // FALSE, you must wait for the request to complete, either with
284 // WaitOnConnect() or by watching wxSOCKET_CONNECTION / LOST
285 // events (please read the documentation).
287 // WaitOnConnect() itself never blocks the GUI (this might change
288 // in the future to honour the wxSOCKET_BLOCK flag). This call will
289 // return TRUE if the connection request completed succesfully, or
290 // FALSE otherwise, which in turn might mean:
291 // a) that the specified timeout ellapsed, or
292 // b) that the connection request failed.
293 // Use IsConnected() to distinguish between these two.
295 // So, in a brief, you should do one of the following things:
297 // For blocking Connect:
299 // bool success = Connect(addr, TRUE);
301 // For nonblocking Connect:
303 // Connect(addr, FALSE);
304 // WaitOnConnect(seconds, millis);
305 // success = IsConnected();
307 // And that's all :-)
309 m_text
->AppendText(_("\nTrying to connect (timeout = 10 sec) ...\n"));
310 m_sock
->Connect(addr
, FALSE
);
311 m_sock
->WaitOnConnect(10);
313 if (m_sock
->IsConnected())
314 m_text
->AppendText(_("Succeeded ! Connection established\n"));
318 m_text
->AppendText(_("Failed ! Unable to connect\n"));
319 wxMessageBox(_("Can't connect to the specified host"), _("Alert !"));
325 void MyFrame::OnTest1(wxCommandEvent
& WXUNUSED(event
))
331 // Disable socket menu entries (exception: Close Session)
335 m_text
->AppendText(_("\n=== Test 1 begins ===\n"));
337 // Tell the server which test we are running
339 m_sock
->Write(&c
, 1);
341 // Send some data and read it back. We know the size of the
342 // buffer, so we can specify the exact number of bytes to be
343 // sent or received and use the wxSOCKET_WAITALL flag. Also,
344 // we have disabled menu entries which could interfere with
345 // the test, so we can safely avoid the wxSOCKET_BLOCK flag.
347 // First we send a byte with the length of the string, then
348 // we send the string itself (do NOT try to send any integral
349 // value larger than a byte "as is" across the network, or
350 // you might be in trouble! Ever heard about big and little
351 // endian computers?)
353 m_sock
->SetFlags(wxSOCKET_WAITALL
);
355 buf1
= _("Test string (less than 256 chars!)");
356 len
= wxStrlen(buf1
) + 1;
357 buf2
= new char[len
];
359 m_text
->AppendText(_("Sending a test buffer to the server ..."));
360 m_sock
->Write((char *)&len
, 1);
361 m_sock
->Write(buf1
, len
);
362 m_text
->AppendText(m_sock
->Error() ? _("failed !\n") : _("done\n"));
364 m_text
->AppendText(_("Receiving the buffer back from server ..."));
365 m_sock
->Read(buf2
, len
);
366 m_text
->AppendText(m_sock
->Error() ? _("failed !\n") : _("done\n"));
368 m_text
->AppendText(_("Comparing the two buffers ..."));
369 if (memcmp(buf1
, buf2
, len
) != 0)
371 m_text
->AppendText(_("failed!\n"));
372 m_text
->AppendText(_("Test 1 failed !\n"));
376 m_text
->AppendText(_("done\n"));
377 m_text
->AppendText(_("Test 1 passed !\n"));
379 m_text
->AppendText(_("=== Test 1 ends ===\n"));
386 void MyFrame::OnTest2(wxCommandEvent
& WXUNUSED(event
))
392 // Disable socket menu entries (exception: Close Session)
396 m_text
->AppendText(_("\n=== Test 2 begins ===\n"));
398 // Tell the server which test we are running
400 m_sock
->Write(&c
, 1);
402 // Here we use ReadMsg and WriteMsg to send messages with
403 // a header with size information. Also, the reception is
404 // event triggered, so we test input events as well.
406 // We need to set no flags here (ReadMsg and WriteMsg are
407 // not affected by flags)
409 m_sock
->SetFlags(wxSOCKET_WAITALL
);
411 wxString s
= wxGetTextFromUser(
412 _("Enter an arbitrary string to send to the server:"),
414 _("Yes I like wxWindows!"));
416 msg1
= (char *)s
.c_str();
417 len
= wxStrlen(msg1
) + 1;
418 msg2
= new char[len
];
420 m_text
->AppendText(_("Sending the string with WriteMsg ..."));
421 m_sock
->WriteMsg(msg1
, len
);
422 m_text
->AppendText(m_sock
->Error() ? _("failed !\n") : _("done\n"));
423 m_text
->AppendText(_("Waiting for an event (timeout = 2 sec)\n"));
425 // Wait until data available (will also return if the connection is lost)
426 m_sock
->WaitForRead(2);
428 if (m_sock
->IsData())
430 m_text
->AppendText(_("Reading the string back with ReadMsg ..."));
431 m_sock
->ReadMsg(msg2
, len
);
432 m_text
->AppendText(m_sock
->Error() ? _("failed !\n") : _("done\n"));
433 m_text
->AppendText(_("Comparing the two buffers ..."));
434 if (memcmp(msg1
, msg2
, len
) != 0)
436 m_text
->AppendText(_("failed!\n"));
437 m_text
->AppendText(_("Test 2 failed !\n"));
441 m_text
->AppendText(_("done\n"));
442 m_text
->AppendText(_("Test 2 passed !\n"));
446 m_text
->AppendText(_("Timeout ! Test 2 failed.\n"));
448 m_text
->AppendText(_("=== Test 2 ends ===\n"));
455 void MyFrame::OnTest3(wxCommandEvent
& WXUNUSED(event
))
461 // Disable socket menu entries (exception: Close Session)
465 m_text
->AppendText(_("\n=== Test 3 begins ===\n"));
467 // Tell the server which test we are running
469 m_sock
->Write(&c
, 1);
471 // This test also is similar to the first one but it sends a
472 // large buffer so that wxSocket is actually forced to split
473 // it into pieces and take care of sending everything before
476 m_sock
->SetFlags(wxSOCKET_WAITALL
);
478 // Note that len is in kbytes here!
480 buf1
= new char[len
* 1024];
481 buf2
= new char[len
* 1024];
483 for (int i
= 0; i
< len
* 1024; i
++)
484 buf1
[i
] = (char)(i
% 256);
486 m_text
->AppendText(_("Sending a large buffer (32K) to the server ..."));
487 m_sock
->Write((char *)&len
, 1);
488 m_sock
->Write(buf1
, len
* 1024);
489 m_text
->AppendText(m_sock
->Error() ? _("failed !\n") : _("done\n"));
491 m_text
->AppendText(_("Receiving the buffer back from server ..."));
492 m_sock
->Read(buf2
, len
* 1024);
493 m_text
->AppendText(m_sock
->Error() ? _("failed !\n") : _("done\n"));
495 m_text
->AppendText(_("Comparing the two buffers ..."));
496 if (memcmp(buf1
, buf2
, len
) != 0)
498 m_text
->AppendText(_("failed!\n"));
499 m_text
->AppendText(_("Test 3 failed !\n"));
503 m_text
->AppendText(_("done\n"));
504 m_text
->AppendText(_("Test 3 passed !\n"));
506 m_text
->AppendText(_("=== Test 3 ends ===\n"));
513 void MyFrame::OnCloseConnection(wxCommandEvent
& WXUNUSED(event
))
519 void MyFrame::OnDatagram(wxCommandEvent
& WXUNUSED(event
))
523 void MyFrame::OnTestURL(wxCommandEvent
& WXUNUSED(event
))
525 // Note that we are creating a new socket here, so this
526 // won't mess with the client/server demo.
529 m_text
->AppendText(_("\n=== URL test begins ===\n"));
530 wxString urlname
= wxGetTextFromUser(_("Enter an URL to get"),
532 _("http://localhost"));
537 // Try to get the input stream (connects to the given URL)
538 m_text
->AppendText(_("Trying to establish connection...\n"));
540 wxInputStream
*data
= url
.GetInputStream();
543 m_text
->AppendText(_("Error: couldn't read from URL\n"));
544 m_text
->AppendText(_("=== URL test ends ===\n"));
548 // Print the contents type and file size
550 s
.Printf(_("Contents type: %s\n"
552 "Starting to download...\n"),
553 url
.GetProtocol().GetContentType().c_str(),
555 m_text
->AppendText(s
);
559 wxFileOutputStream
sout(wxString("test.url"));
561 m_text
->AppendText(_("Results written to file: test.url\n"));
562 m_text
->AppendText(_("Done.\n"));
563 m_text
->AppendText(_("=== URL test ends ===\n"));
568 void MyFrame::OnSocketEvent(wxSocketEvent
& event
)
570 wxString s
= _("OnSocketEvent: ");
572 switch(event
.SocketEvent())
574 case wxSOCKET_INPUT
: s
.Append(_("wxSOCKET_INPUT\n")); break;
575 case wxSOCKET_LOST
: s
.Append(_("wxSOCKET_LOST\n")); break;
576 case wxSOCKET_CONNECTION
: s
.Append(_("wxSOCKET_CONNECTION\n")); break;
577 default : s
.Append(_("Unexpected event !\n")); break;
580 m_text
->AppendText(s
);
584 // convenience functions
586 void MyFrame::UpdateStatusBar()
590 if (!m_sock
->IsConnected())
592 s
.Printf(_("Not connected"));
598 m_sock
->GetPeer(addr
);
599 s
.Printf(_("%s : %d"), (addr
.Hostname()).c_str(), addr
.Service());
604 m_menuSocket
->Enable(CLIENT_OPEN
, !m_sock
->IsConnected() && !m_busy
);
605 m_menuSocket
->Enable(CLIENT_TEST1
, m_sock
->IsConnected() && !m_busy
);
606 m_menuSocket
->Enable(CLIENT_TEST2
, m_sock
->IsConnected() && !m_busy
);
607 m_menuSocket
->Enable(CLIENT_TEST3
, m_sock
->IsConnected() && !m_busy
);
608 m_menuSocket
->Enable(CLIENT_CLOSE
, m_sock
->IsConnected());