|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
ContentsIntroductionThis class is designed to replace the buggy MFC It allows to create both TCP or UDP socket types operating in client or server configuration, integrates a dynamic buffer that stores all incoming data allowing delayed access, and provides async events notification. Asynchronous notifications are triggered for:
To read incoming data, there are four possibilities:
To send data, you can choose between:
Other functions let you specify the string EOL format, to query socket state, to change UDP or TCP receiving buffer, and to query internal data buffer state. BackgroundThe first time I wrote a network application for a PDA, I realized that the
Using the codeBefore explaining in detail how to use every single function of the class, I think you should known that the Creating a socketTo use bool Create(int socketType, int bufferSize = 0); //Examples: mySocket->Create(SOCK_STREAM); mySocket->Create(SOCK_DGRAM); mySocket->Create(SOCK_STREAM, 4096);
Return value is int GetLastError() //returned error is obtained from a WSAGetLastError() call Now, you can decide to make a client or a server socket. Making a client socketTo make a client socket, call: bool Connect(CString &addr, UINT remotePort); //Examples: mySocket->Connect("192.168.0.20", 3000); mySocket->Connect("www.someServer.com", 5003);
Return value is
Now, you can use your socket to send and read data. However, you should first learn how notifications (events) work, otherwise you won't know when new data is available for reading or if your socket is disconnected for some reason. Making a server socketTo make a server socket, call: bool Accept(UINT localPort, int maxConn = SOMAXCONN); //Examples: mySocket->Accept(3000); mySocket->Accept(5003, 1);
Return value is
It provides a service socket that can be used to accept the connection. You'll notice that this is a virtual function. All events are virtual functions. In fact, you cannot use So, when void AcceptServiceSocket(SOCKET serviceSocket);
Now, you can use this new socket to receive and send messages. A quick example (for TCP)This is a quick example to explain the //This is a subclassed CCESocket class CMySocket : public CCESocket { public: CMySocket(); CMySocket(CWnd* parent); virtual ~CMySocket(); void SetParent(CWnd* parent) {m_parent = parent;} virtual bool OnAccept(SOCKET serviceSocket); virtual void OnReceive(); virtual void OnClose(int closeEvent); protected: CWnd* m_parent; }; CMySocket::CMySocket() : CCESocket() { m_parent = NULL; } CMySocket::CMySocket(CWnd* parent) : CCESocket() { m_parent = parent; } CMySocket::~CMySocket() { } bool CMySocket::OnAccept(SOCKET serviceSocket) { if(m_parent) { ::PostMessage(m_parent->m_hWnd, ON_ACCEPT, (WPARAM) serviceSocket, (LPARAM) this); return TRUE; } return FALSE; } void CMySocket::OnReceive() { if(m_parent) ::PostMessage(m_parent->m_hWnd, ON_RECEIVE, NULL, (LPARAM) this); } void CMySocket::OnClose(int closeEvent) { if(m_parent) ::PostMessage(m_parent->m_hWnd, ON_CLOSE, (WPARAM) closeEvent, (LPARAM) this); }
class MyApp : public CDialog { public: ... afx_msg LRESULT OnAccept(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnReceiveData(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnDisconnected(WPARAM wParam, LPARAM lParam); ... protected: CMySocket *m_server; CMySocket *m_serviceSocket; ... }; BOOL MyApp::OnInitDialog() { bool serverStarted; ... m_server = new CMySocket(this); if(serverStarted = m_server->Create(SOCK_STREAM)) serverStarted = m_server->Accept(somePortNumber); if(!serverStarted) //Recovery code ... } LRESULT MyApp::OnAccept(WPARAM wParam, LPARAM lParam) { m_serviceSocket = new CMySocket(this); m_serviceSocket->AcceptServiceSocket((SOCKET) wParam); m_serviceSocket->SendLine("Hello!"); return 0; }
DisconnectingTo disconnect a socket, you can call: void Disconnect(); //Example: mySocket->Disconnect(); After a disconnect, you must call NotificationsWe have already seen the As soon as you get new data, the following event is called (if you have redefined its virtual function): virtual bool OnReceive(char* buf, int len);
This notification is called directly from the receiving thread to notify that there is new data in the queue. This is the first notification of this kind, and offers the possibility to get the data without buffering it. If you accept the packet, then return virtual void OnReceive(); This event only notifies you that there is data in the buffer. I'll show you later how to read data from the buffer. If a connection closes, for any reason, you receive: virtual void OnClose(int closeEvent);
If your socket is a server and, for some reason, the read (UDP) or accept (TCP) thread fails, both TCP or UDP sockets will return an //Respawning a TCP server: (OnDisconnected //implementation of MyApp example class) LRESULT MyApp::OnDisconnected(WPARAM wParam, LPARAM lParam) { CCESocket *disconnectedSocket = (CCESocket*) lParam; if(disconnectedSocket == m_server) { Sleep(100); if(m_server->Create(SOCK_STREAM)) if(m_server->Accept(somePortNumber)) return 0; //Recovery code } return 0; } As stated at the beginning, keep in mind that these functions are called from another thread, not from the main application thread. If you need to execute something in the window thread, you should send a message to it with Reading dataYou already know one of the four ways to read data: direct read through the first You can read binary data using: int Read(char* buf, int len); //Example: char *buf = NULL; int count; int len = mySocket->GetDataSize(); if(len > 0) { buf = new char[len]; count = mySocket->Read(buf, len); }
Return value is the number of bytes actually read. To read a string, use the following function: bool ReadString(CString &str); //Example: CString str; while(mySocket->GetDataSize() > 0 && mySocket->ReadString(str)) doSomethingWithTheString(str);
Return value is To read the head packet stored in the buffer, use: bool GetPacket(char*& buf, int* len); //Example: char *buf = NULL; int len; while(mySocket->GetNumPackets() > 0) { if(mySocket->GetPacket(buf, &len)) useTheData(buf, len); if(buf != NULL) delete[] buf; }
Return value is Sending dataYou have three functions to send data. Binary send: int Send(const char* buf, int len); //Example: int count; count = mySocket->Send(myBuffer, myBufferSize);
Return value is the number of bytes sent, or To send a string, use one of the following functions: int Send(CString& str); int SendLine(CString &str); //Examples: CString msg = "My beautiful string"; mySocket->Send(msg); mySocket->Send("Hello!"); mySocket->SendLine(msg); Both send the string Other functionalitiesint GetDataSize();
Returns the total data size queued in the buffer. int GetNumPackets();
Returns the number of packets queued in the buffer. int GetPacketSize();
Returns the size of the head packet in the queue (next packet to to be retrieved). int GetLastError(); //returned error is obtained from a WSAGetLastError() call Returns the error code of the last error. int GetSocketType();
Returns int GetSocketState();
Returns one of the following states:
void SetBufferSize(int bufSize);
Call this function to modify the buffer size. You can call it at any time, even if the socket is already connected. This is useful if you want to change the buffer size after a void SetEolFormat(eolFormat eol);
Sets the new EOL format for
| ||||||||||||||||||||||