Saturday, January 10, 2009

Sending and Receiving Data using UDP between C++ and C# Applications

Maybe you want to share some data between different applications. For example once I had to share some data between an application coded in C++ and a C# one. Probably the first thing that might come into your mind would be sharing data in some files, and then lock them when reading and writing. I think when you are dealing with some applications that might have couple of thousands of codes the idea of sharing files would make your application slow, and locking the shared resources would be a headache, so I recommend using socket programming. A socket is an abstraction through which an application may send and receive data, in pretty much the same way as opening a file to read and write data. Different types of sockets correspond to different protocols. I will give you a brief description of TCP/IP protocol which has the main types of stream sockets and datagram sockets. Stream sockets use TCP and datagram sockets use UDP.

The .NET framework has two classes for TCP which are TCPClient and TCPListener. A TCPClient initiates the communication with a server which is waiting for the connection. TCP is connection oriented and UPD is connectionless, which means that UPD sockets do not need to be connected before being used. Another difference between TCP and UDP is that there is no guarantee that a message sent via a UDP socket will arrive at its destination, and messages can be delivered in a different order than they were sent. So why use UDP?

The most important reason is performance. When you are sending small amount of data, using TCP might double number of messages being sent and UDP provides minimal overhead platform.

Here is a sample code for sending and receiving data in C#. you have to add System.Net and System.Net.Sockets namespaces.


using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

namespace UDPClient

{

class Program

{

static void Main(string[] args)

{

SendUDPData("192.168.0.11", 27250, "This is UDP Test");

}

static void SendUDPData(string ServerIP, int Port,string Mess)

{

UdpClient client = new UdpClient();

byte[] SendPacket = Encoding.ASCII.GetBytes(Mess);

try

{

client.Send(SendPacket, SendPacket.Length, ServerIP, Port);

Console.WriteLine("Sent {0} bytes to the server", SendPacket.Length);

}

catch (Exception ex)

{

Console.WriteLine(ex.Message);

}

client.Close();

}

}

}


You can receive data using the server program as follows:

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

namespace UDPServer

{

class Program

{

static void Main(string[] args)

{

RecData(27250);

}

static void RecData(int Port)

{

UdpClient client = null;

try

{

client = new UdpClient(Port);

}

catch (Exception ex)

{

Console.WriteLine(ex.Message);

}

IPEndPoint RemoteServer = new IPEndPoint(IPAddress.Any, 0);

for (; ; )

{

try

{

byte[] RecPacket = client.Receive(ref RemoteServer);

Console.WriteLine("Connected to the client {0}, {1}", RemoteServer, Encoding.ASCII.GetString(RecPacket));

}

catch (Exception ex)

{

Console.WriteLine(ex.Message);

}

}

}

}

}

As I mentioned at the beginning of the post, imagine you want to share data between a C# and a C++ application, so here is the UDP client and server in C++. You have to add winsick2.h and WS2_32.Lib to your project. For adding WS2_32.Lib, open project properties, click on Linker, and then Input, and in front of the Additional Dependencies enter then name of the .Lib file which is WS2_32.Lib.


#include "iostream"

#include "winsock2.h"

using namespace std ;

void main()

{

WSADATA wsaData;

SOCKET SendSocket;

sockaddr_in RecvAddr;

int Port = 28250;

char SendBuf[32]="From port 27250";

int BufLen = 32;

char* IP_ADDRESS_S="192.168.0.11";

WSAStartup(MAKEWORD(2,2), &wsaData);

SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

RecvAddr.sin_family = AF_INET;

RecvAddr.sin_port = htons(Port);

RecvAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS_S);

cout<<"Sending a datagram to the receiver...";

sendto(SendSocket, SendBuf, BufLen, 0, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));

cout<<"Finished sending. Closing socket.";

closesocket(SendSocket);

cout<<"Exiting.";

WSACleanup();

}


The server program in C++ is as follows:

#include "iostream"

#include "winsock2.h"

using namespace std ;

void main()

{

WSADATA wsaData;

SOCKET RecvSocket;

sockaddr_in RecvAddr;

int Port = 27250;

char RecvBuf[1024];

int BufLen = 1024;

sockaddr_in SenderAddr;

int SenderAddrSize = sizeof(SenderAddr);

WSAStartup(MAKEWORD(2,2), &wsaData);

RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

RecvAddr.sin_family = AF_INET;

RecvAddr.sin_port = htons(Port);

RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(RecvSocket, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));

cout<<"Receiving datagrams...";

recvfrom(RecvSocket, RecvBuf, BufLen, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize);

cout<

cout<

cout<<"Finished receiving. Closing socket.";

closesocket(RecvSocket);

cout<<"Exiting.";

WSACleanup();

}


You can use client and server codes and communicate between applications. You need to use a thread to do the receiving task, because UDP receiver blocks until a datagram arrives from a remote host. So you need to use a thread to receive data, and don’t forget to abort the thread before exiting your application. I am planning to have a post about threads in future.


2 comments:

  1. This is useful - thanks. There seem to be two unfinished lines in the C++ UDP server, however. Lines 22 & 23 unfinished cout<< just echo garbage.

    I found cout << RecvBuf << end; to be more helpful.

    ReplyDelete