YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   Home Products | Purchase Support | Downloads  
View in English
View in Japanese
View in
참고
View in Franšais
View in Italiano
View in 中文(繁體)
Download Evaluation
Pricing & Purchase?
E-XD++Visual C++/ MFC Products
Overview
Features Tour 
Electronic Form Solution
Visualization & HMI Solution
Power system HMI Solution
CAD Drawing and Printing Solution

Bar code labeling Solution
Workflow Solution

Coal industry HMI Solution
Instrumentation Gauge Solution

Report Printing Solution
Graphical modeling Solution
GIS mapping solution

Visio graphics solution
Industrial control SCADA &HMI Solution
BPM business process Solution

Industrial monitoring Solution
Flowchart and diagramming Solution
Organization Diagram Solution

Graphic editor Source Code
UML drawing editor Source Code
Map Diagramming Solution

Architectural Graphic Drawing Solution
Request Evaluation
Purchase
ActiveX COM Products
Overview
Download
Purchase
Technical Support
  General Q & A
Discussion Board
Contact Us

Links

Get Ready to Unleash the Power of UCanCode .NET

WinCE MFC TCP SOCKET AND UDP SOCKET Sample Codes


First time here?

Product Tour
E-XD++ Workflow Component product walkthrough

Screenshots
Applications built on E-XD++ Workflow Component

Product feature comparison

Powerful, flexible, and easy to use Diagram Components.
Powerful and flexible enough to create diagrams exactly the way you want them to appear. So easy to use that you will be able to prototype your application in just a few minutes.

Feature rich.
With features such as automatic layout, multiple layers, collapsible sub-graphs, snap-to connection points, XML, SVG, and more, E-XD++ Have the power and flexibility you need to create sophisticated diagrams, quickly and easily. Events such as click, double-click, hover, select, rubber-band select, copy, delete, resize and move are supported. Operations such as drag-and-drop, unlimited undo/redo, and clipboard operations are common and complex, and are expected by today's sophisticated users. it full supports importing ArcGis, SVG and DXF File format.

Performance and Scalability.
UCanCode E-XD++ Capable of handling many thousands of nodes and edges, up to hundreds of thousands depending upon the complexity of the nodes you wish to draw and the operations you wish to allow. Our graphical classes are extremely lightweight objects enabling outstanding performance.

Save Time and Money and gain Reliability.
A diagram is worth 1,000 words, and E-XD++ is shipped with more than 500,000 lines of well designed and well tested code! It is used by hundreds of the world's most quality conscious companies.  It will saves you thousands of hours of complex coding and years of maintenance.

 

 


Contents

1

This class is designed to replace the buggy MFC CCeSocket class for the WinCE (Pocket PC) platform. However, it works even on Win32 systems (tested on Win2K and WinXP).

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:

  • Incoming data
  • Closed connections
  • Accepted clients (only for TCP)

To read incoming data, there are four possibilities:

  • Direct read: read data as they arrive. In this way, data is not stored in the internal buffer.
  • Binary read.
  • Text read: it's possible to read single strings.
  • Packet read: you can read single packets, exactly as they were received.

To send data, you can choose between:

  • Binary mode.
  • String mode.
  • String mode with auto EOL termination.

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.

2

The first time I wrote a network application for a PDA, I realized that the CCeSocket, that comes with MFC, was completely useless. It not only lacks asynchronous notifications but it also consumes more resources than is really necessary, and must be wrapped in the CSocketFile/CArchive framework to use advanced load/store operations. So I decided to write a completely new socket wrapper for the WinCE OS that is small, efficient, general purpose, and with advanced read/send functions. I use it extensively in a human robot interface for the RoboCup Robot@Home league.

3

Before explaining in detail how to use every single function of the class, I think you should known that the CCESocket uses two independent threads, one for receiving data, and another for accepting connections (if the socket is accepting). Both threads use blocking calls to Winsock API functions to minimize CPU usage. You should be aware of the existence of these threads because they call events (virtual functions, see Notifications), so when you receive an event, you're on a different thread than the main one.

Creating a socket

To use CCESocket, you first have to call the Create function:

Collapse | Copy Code
bool Create(int socketType, int bufferSize = 0);

//Examples:
mySocket->Create(SOCK_STREAM);
mySocket->Create(SOCK_DGRAM);
mySocket->Create(SOCK_STREAM, 4096);
  • socketType: can be SOCK_STREAM for TCP, or SOCK_DGRAM for UDP.
  • bufferSize: you can specify the buffer size for incoming packets. Otherwise, the default values will be used: 1024 bytes for TCP, and 2048 bytes for UDP.

Return value is TRUE if the socket is created successfully, FALSE if an error occurs. You can always query the last error code with the function:

Collapse | Copy Code
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 socket

To make a client socket, call:

Collapse | Copy Code
bool Connect(CString &addr, UINT remotePort);

//Examples:
mySocket->Connect("192.168.0.20", 3000);
mySocket->Connect("www.someServer.com", 5003);
  • addr: is the remote host address. It can be an IP number or the host name.
  • remotePort: is the remote host port to connect to.

Return value is TRUE if the connection was successfully established, FALSE if an error occurs.

  • TCP socket: this function really connects the two computers. In this case, if you want to make a new connection, you have to disconnect the socket first.
  • UDP socket: CCESocket doesn't establish a real connection, it only saves the passed address to the sent data. In this case, you can reconnect to another address without first disconnecting.

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 socket

To make a server socket, call:

Collapse | Copy Code
bool Accept(UINT localPort, int maxConn = SOMAXCONN);

//Examples:
mySocket->Accept(3000);
mySocket->Accept(5003, 1);
  • localPort: is the local port to bind for incoming requests.
  • maxConn: is the maximum length of the queue for pending connections.

Return value is TRUE if Accept is successful, FALSE if an error occurs. This function will bind the socket to a local port waiting for connections.

  • UDP socket: when a UDP packet is received from a client, CCESocket will trigger a normal OnReceive event (see Notifications). After receiving this data, you can use the same socket to send data to the remote client. UDP acts blindly, you never know if someone is really listening, and doesn't require service sockets like TCP does.
  • TCP socket: when a new connection is accepted, CCESocket will trigger the OnAccept event:
    Collapse | Copy Code
    virtual bool OnAccept(SOCKET serviceSocket)

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 CCESocket as is, you must subclass it and redefine virtual functions for the events that you want to catch.

So, when CCESocket calls your OnAccept function, you can refuse the connection, returning FALSE, or accept the connection, returning TRUE. If you accept the connection, you must create a new (subclassed) CCESocket and pass the service socket to its AcceptServiceSocket function (you do not have to call the Create function first):

Collapse | Copy Code
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 OnAccept/AcceptServiceSocket functions.

Collapse | Copy Code
//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);
}

ON_ACCEPT, ON_RECEIVE, and ON_CLOSE are window messages passed to the main application. The latter could be something like this (note: the code is dirty and is intended only to show the necessary steps to set up a server):

Collapse | Copy Code
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;
}

OnAccept, OnReceiveData, and OnDisconnect are triggered by the ON_ACCEPT, ON_RECEIVE, and ON_CLOSE events posted by CMySocket. However, I only defined the OnAccept function for this example. I think the code is so simple that it doesn't need any comment :-)

Disconnecting

To disconnect a socket, you can call:

Collapse | Copy Code
void Disconnect();

//Example:
mySocket->Disconnect();

After a disconnect, you must call Create again if you want to use the socket again.

Notifications

We have already seen the OnAccept event. Let's now analyse OnReceive and OnClose. To receive these events, you have to subclass CCESocket and provide new virtual functions, as already seen in the CMySocket example class.

As soon as you get new data, the following event is called (if you have redefined its virtual function):

Collapse | Copy Code
virtual bool OnReceive(char* buf, int len);
  • buf: is the received data packet.
  • len: it is the packet length.

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 TRUE. In this case, you're responsible for deleting the buffer after its use. If you refuse the data, then return FALSE. In this case, the packet will be stored in the internal buffer and you'll receive a new notification:

Collapse | Copy Code
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:

Collapse | Copy Code
virtual void OnClose(int closeEvent);
  • closeEvent: it is an enum that can be:
    • CCESocket::EVN_CONNCLOSED (=0)
    • CCESocket::EVN_CONNLOST (=1)
    • CCESocket::EVN_SERVERDOWN (=2)
  • TCP socket: you receive EVN_CONNCLOSED if the other peer disconnects. If you are a client and wants to make a new connection, call Create followed by Connect. If you are a server, then simply release (delete) the service socket.
  • UDP socket: you receive EVN_CONNLOST if the other peer "disconnects". This happens only if you try to send data to a disconnected peer (to my knowledge, this should not happen, however, this is what I experimented using the Winsock APIs). If you are a client and wants to make a new connection, call Connect. If you are a server, you can use or ignore the event, it doesn't interfere with the server operation. Note that if you continue to send data to a disconnected peer, CCESocket will ignore your trials, and send functions will return 0 sent bytes.

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 EVN_SERVERDOWN event. In this case, to respawn the server, you must call Create (only if TCP) followed by Accept:

Collapse | Copy Code
//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 PostMessage (as seen in the CMySocket example). This is required for MFC objects. They don't work if passed among threads, you should use these objects in the same thread where they are defined.

Reading data

You already know one of the four ways to read data: direct read through the first OnReceive event. The remaining functions access data directly from the internal buffer. You'll typically call one of them after receiving the OnReceive event. Data remains available even after a socket disconnection.

You can read binary data using:

Collapse | Copy Code
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);
}
  • buf: the buffer that will receive the data. It must be already allocated.
  • len: buffer size.

Return value is the number of bytes actually read.

To read a string, use the following function:

Collapse | Copy Code
bool ReadString(CString &str);

//Example:
CString str;
while(mySocket->GetDataSize() > 0 && 
      mySocket->ReadString(str))
    doSomethingWithTheString(str);
  • str: is the read sting.

Return value is TRUE if the string was read, FALSE if there was no string to read. A string is an array of bytes that begins at the current buffer location and terminates with an EOL. This value can be set with the SetEolFormat function (see later).

To read the head packet stored in the buffer, use:

Collapse | Copy Code
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;
}
  • buf: a pointer to the buffer that will contain the packet data. The buffer will be internally allocated to match the packet size. You have to delete it after its use.
  • len: it will contain the buffer size.

Return value is TRUE if the packet was successfully retrieved, FALSE if there was no packet to retrieve.

Sending data

You have three functions to send data.

Binary send:

Collapse | Copy Code
int Send(const char* buf, int len);

//Example:
int count;
count = mySocket->Send(myBuffer, myBufferSize);
  • buf: the buffer that contains the data to send.
  • len: buffer size.

Return value is the number of bytes sent, or SOCKET_ERROR if an error occurs. Note: you cannot send data with a listening TCP socket.

To send a string, use one of the following functions:

Collapse | Copy Code
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 str. However, the latter adds an EOL to the string. The EOL is set with the SetEolFormat function (see later).

Other functionalities

Data query functions

Collapse | Copy Code
int GetDataSize();

Returns the total data size queued in the buffer.

Collapse | Copy Code
int GetNumPackets();

Returns the number of packets queued in the buffer.

Collapse | Copy Code
int GetPacketSize();

Returns the size of the head packet in the queue (next packet to to be retrieved).

Socket query functions

Collapse | Copy Code
int GetLastError();
//returned error is obtained from a WSAGetLastError() call

Returns the error code of the last error.

Collapse | Copy Code
int GetSocketType();

Returns SOCK_STREAM for TCP sockets, SOCK_DGRAM for UDP sockets.

Collapse | Copy Code
int GetSocketState();

Returns one of the following states:

    • CCESocket::NONE (=0)
    • CCESocket::DISCONNECTED (=1)
    • CCESocket::CREATED (=2)
    • CCESocket::CONNECTED (=3)
    • CCESocket::ACCEPTING (=4)

Other functions

Collapse | Copy Code
void SetBufferSize(int bufSize);
  • bufSize: new buffer size.

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 AcceptServiceSocket call.

Collapse | Copy Code
void SetEolFormat(eolFormat eol);
  • eolFormat: may be one the following:
    • CCESocket::EOL_NULL (=0)
    • CCESocket::EOL_LFCR (=1)
    • CCESocket::EOL_CR (=2)

Sets the new EOL format for SendLine and ReadString functions.

News:

1 UCanCode Advance E-XD++ CAD Drawing and Printing Solution Source Code Solution for C/C++, .NET V2017 is released!

2 UCanCode Advance E-XD++ HMI & SCADA Source Code Solution for C/C++, .NET V2017 is released!

3 UCanCode Advance E-XD++ GIS SVG Drawing and Printing Solution Source Code Solution for C/C++, .NET V2017 is released!


Contact UCanCode Software

To buy the source code or learn more about with:

 

Ask any questions by MSN: ucancode@hotmail.com Yahoo: ucan_code@yahoo.com


 

Copyright ?1998-2011 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net