Skip to main content

Blackberry 10 cascades - client side socket programming

Blackberry 10 has full support for BSD Sockets API. All the routines one can expect from BSD Sockets are available in Blackberry 10. But cascades make socket programming much easier.
In this post we will discuss client side socket programming in Blackberry 10 using cascades.

You can study about BSD Sockets API support in Blackberry 10 here.

Before starting to use Cascades socket API you have to add this line to your .pro file
QT+= network
Cascades API provide a high level class QTcpSocket which makes writing client side socket code very easy.

Include following files in your cpp file
#include <QtNetwork/QAbstractSocket>
#include <QtNetwork/QTcpSocket>
Any client side socket app performs following operations
1) Connect to server
2) Send / Receive data
3) Close connection
Connecting to server
QTcpSocket provides a function connectToHost which takes IP Address/Hostname (QString) , port (quint16) and OpenMode (default value is ReadWrite) as parameters. connectToHost is inherited from QAbstractSocket class. So lets connect to our server using connectToHost function.
QTcpSocket cSocket;
cSocket.connectToHost("192.168.0.1",80);
We have directed QTcpSocket to connect to our specified host on 80 port. But how do we know after the function returns that whether connection was successful or not ? QTcpSocket emits 3 important signals
1) connected
2) error
3) disconnected

QTcpSocket attempts to connect asynchronously so the function connectToHost will return immediately without any information. We have to connect slots to the above mentioned signals to get the status.
First lets write sample slots to connect
//slot to handle connected signal
void MyClientApp::onSocketConnect()
{
    //do something when socket is connected
}
//slot to handle error signal
void MyClientApp::onSocketError(QAbstractSocket::SocketError err)
{
    //do something on error
    if (err==QAbstractSocket::ConnectionRefusedError){
    }else if (err==QAbstractSocket::HostNotFoundError){
    }else if (err==QAbstractSocket::NetworkError){
    }else{
    }
}
//slot to handle connected signal
void MyClientApp::onSocketDisconnect()
{
    //do something when socket is disconnected
Now we will connect our slots to the signals of QTcpSocket.
connect(&cSocket, SIGNAL(connected()),this, SLOT(onSocketConnect()));
connect(&cSocket, SIGNAL(disconnected()),this, SLOT(onSocketDisconnect()));
connect(&cSocket, SIGNAL(error(QAbstractSocket::SocketError)),this,
             SLOT(onSocketError(QAbstractSocket::SocketError)));
Connecting synchronously using QTcpSocket
QTcpSocket provides a function waitForConnected which takes milliseconds as parameters. This function keep on waiting until specified milliseconds are elapsed or socket is connected. This function can be used to make our connection code synchronous. It returns true if connection is successful otherwise it returns false.
Following is an example usage
QTcpSocket cSocket;
cSocket.connectToHost("192.168.0.1",80);
//wait for 5 seconds
if (cSocket.waitForConnected(5000))
{
    //do something when socket is connected
}
else
{
    //do something if connection fails
}
Send/Receive data
Once our connection is established , next step is to send or receive data from socket. QTcpSocket implements read/write functions of QIODevice to receive and send data over socket.
write has 3 overloads
qint64 QIODevice::write ( const char * data, qint64 maxSize)
qint64 QIODevice::write ( const char * data)
qint64 QIODevice::write ( const QByteArray & byteArray)
First overload sends data stored in "const char *data" parameter upto maxSize from data. It returns number of bytes actually written or -1 on error.
Second overload sends data passed as parameter and returns number of bytes actually written or -1 on error
Third overload sends data in byteArray parameter and returns number of bytes actually written or -1 on error.

Here is a sample code that uses second overload of write to continuously send data on socket
char *data=(char *)malloc(1024);
fillDataToSend(data); //dummy call to fill buffer with data
int written=0;
while((written=cSocket.write((const char *)data))!=-1)
{
    //data written
}
For reading data we have 2 overloads of read function
qint64 QIODevice::read ( char * data, qint64 maxSize )
QByteArray QIODevice::read ( qint64 maxSize ) 
First overload reads at most maxSize of bytes into data parameter and returns the number of bytes actually read or -1 on error. 0 is returned if no bytes are available to read.
Second overload reads at most maxSize of bytes and return the data as QByteArray. This function returns empty QByteArray when no data is read but it has no mechanism to report error.

Here is a sample code that reads data from socket using first overload
char *data=(char *)malloc(1024);
int read=0;
while((read=cSocket.read(data,1024))!=-1)
{
    //data read now do something with it
}
Closing the connection
Once we are done with sending/receiving of data , our last step is to close the connection. QTcpSocket has two functions to perform this task
1) disconnectFromHost
2) close

disconnectFromHost waits for all data (pending) to be written and then close the connection and emits disconnected signal.
close function close the socket and releases the memory

Here is a sample code to close the connection
cSocket.disconnectFromHost();
cSocket.close();

Comments

Popular posts from this blog

Decoding JPEG image file using libavcodec

I got a chance to work on a video encoding application that decodes series of jpeg files and convert them into ogg theora video file. I used the infamous libavcodec library that is used in FFMPEG . I decided to write blog posts explaining how I decode jpeg images and convert them into ogg video file. This is the first part and in this I will explain how to decode jpeg images using libavcodec. To learn how to write decoded images as a ogg video file please read http://random-stuff-mine.blogspot.com/2017/07/encoding-raw-images-to-ogg-theora-video.html Before reading this blog post you must be aware of using and setting up libavcodec. I highly recommend this tutorial to get basics of using libavcodec http://www.ffmpeg.org/doxygen/0.6/api-example_8c-source.html Allocating input format context We will first allocate input format for reading the file. We will use avformat_open_input function that will allocate AVFormatContext structure passed to it , the function detects input typ

CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information

I created a new Blazor Server app in Visual Studio 2019 and tried to run it. But I was getting this error CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information. I couldn't find any reason or solution to this problem. I tried creating the project multiple times but same error. I created a new .Net Core Web App and added a new razor component and included that component in a razor page (cshtml file) like this @(await Html.RenderComponentAsync<GeofenceWork>(RenderMode.ServerPrerendered)) and <component type="typeof(GeofenceWork)" render-mode="serverprerendered" /> As soon as I navigate to this page that has component added I got the same error: CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information. This was very frustrating. After hours of trying and searching I figured out the solution. 

Encoding raw images to Ogg Theora video using libavcodec

In one of the blog posts we learned how to decode jpeg images using libavcodec. This is the second part of that post. In this we will learn how to encode decoded images (raw images) to theora and write them in ogg video file. In the end of the first part we saved our raw image in raw_data variable and its length in raw_data_size variable. Lets assume that we packaged all our decoding code in one function called "decode_jpeg_image" which has following signature int decode_jpeg_image(char *filename,int file_name_size,uint8_t *raw_data,int *raw_data_size) filename = name of jpeg file to decode file_name_size = length of jpeg file's name raw_data = contains decoded raw image on return raw_data_size = contains length of raw_data on return Now let's start working on how to encode this image in raw_data to theora and write that image to ogg video file. Finding Theora encoder We first have to find encoder for THEORA which is represented by AVCodec structure. He