Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

[RESOLVED] C++ convert to VB.Net

stulish

New member
Joined
May 12, 2016
Messages
13
Hi Guys,

I have been asked to create a module that receives images over a network and some saple code that works, my problem is the sample code is C++ and i have tried to understand it but with not much success.

The code is only 91 lines long with line spaces (see below):

Code:
#include "stdafx.h"
#include <winsock2.h>

struct ImageRxHeader
{
    char            m_token[6];
    unsigned short    m_headerCrc;        // CRC of rest of header
    unsigned short    m_headerVersion;
    unsigned long    m_headerLength;        // octets
    unsigned long    m_dataLength;        // octets
    unsigned long    m_timeSecs;
    unsigned long    m_timeNanoSecs;
    unsigned short    m_diffTime;            // msecs
    unsigned long    m_maxNum;            // packets
    unsigned long    m_actNum;            // packets
    unsigned long    m_streamLength;        // octets
    unsigned char    m_device;
    unsigned char    m_channel;
    unsigned long    m_deviceIp;
    unsigned long    m_devicePort;
    char            m_datatype[16];
    char            m_status[80];
};

DWORD WINAPI clientThread(void *context)
{
    SOCKET s = (SOCKET)context;
    ImageRxHeader vlh;
    int err = recv(s,(char *)&vlh,68,0);

    char *pBuf = new char [vlh.m_dataLength];
    char *pData = pBuf;
    unsigned int bytesLeft = vlh.m_dataLength;
    unsigned int count = 0;
    while ((err = recv(s,pData,bytesLeft,0)) > 0)
    {
        count += err;
        pData += err;
        bytesLeft -= err;
    }

    bool fileWritten = false;
    int index = 0;
    do
    {
        char fileName[80];
        sprintf(fileName,"c:\\test%04d.png",index++);
        unsigned long attrib = GetFileAttributes(fileName);
        if (attrib == INVALID_FILE_ATTRIBUTES)
        {
            FILE *pf = fopen(fileName,"wb");
            fwrite(pBuf,1,vlh.m_dataLength,pf);
            fclose(pf);
            fileWritten = true;
        }
    } while (!fileWritten);
    
    delete pBuf;

    return 0;
}



int _tmain(int argc, _TCHAR* argv[])
{

    WSADATA wsd;
    int err = WSAStartup(MAKEWORD(2,2),&wsd);
    
    SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    sockaddr_in sa;
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = 0;
    sa.sin_port = htons(7096);

    bind(s,(const sockaddr *)&sa,sizeof(sa));
    listen(s,5);

    bool keepGoing = true;

    while (keepGoing)
    {
        sockaddr_in clientAddr;
        int cliLen = sizeof(clientAddr);
        SOCKET clientSocket = accept(s,(sockaddr *)&clientAddr,&cliLen);
        DWORD threadId;
        CreateThread(0,0,clientThread,(void *)clientSocket,0,&threadId);
    }
    return 0;
}

I know the IP Address of the Server 172.31.16.17 and the port should be 7096 that it receives the data on. But looking at the C++ code i cant see where it opens a TCP connection with these attributes, i can see the port number, but can not see how it passes the IP address??

I have tried creating some small VB apps using TCPCLient and Network Streams but the different ways i have tried all wont connect (below is one way):

Code:
Imports System.Net.Sockets
Imports System.Threading.Thread
Imports System.Net
Imports System.Text
Public Class Form1
    Dim ClientSocket As New TcpClient
    Dim ServerStream As NetworkStream
    Dim ServerAddress As String = "172.31.16.17" ' Set the IP address of the server
    Dim PortNumber As Integer = 7096 ' Set the port number used by the server
    Dim OutStream As Byte() 
    Dim ReceivedData As String
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    End Sub
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ClientSocket.Connect(ServerAddress, PortNumber)
        Dim inStream(100000) As Byte
        ServerStream = ClientSocket.GetStream()
        ServerStream.Read(inStream, 0, CInt(ClientSocket.ReceiveBufferSize))
        ReceivedData = Encoding.ASCII.GetString(inStream)
        HandleReceivedDate(ReceivedData)
    End Sub
    Private Sub HandleReceivedDate(ByVal msg As String)
        TextBox1.AppendText(msg & vbCrLf)
    End Sub

View attachment 137893

The form just has one button and a textbox as shown in the image, but i keep getting the following error:

System.Net.Sockets.SocketException was unhandled
ErrorCode=10061
HResult=-2147467259
Message=No connection could be made because the target machine actively refused it 172.31.16.17:7096
NativeErrorCode=10061
Source=System
StackTrace:
at System.Net.Sockets.TcpClient.Connect(String hostname, Int32 port)
at WindowsApplication1.Form1.Button1_Click(Object sender, EventArgs e) in C:\KH DLL\Try 1\WindowsApplication1\WindowsApplication1\Form1.vb :line 16
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventAr gs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.O nMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.W ndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallba ck(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchM essageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager. System.Windows.Forms.UnsafeNativeMethods.IMsoCompo nentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.Run MessageLoop(Int32 reason, ApplicationContext context)
at Microsoft.VisualBasic.ApplicationServices.WindowsF ormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsF ormsApplicationBase.DoApplicationModel()
at Microsoft.VisualBasic.ApplicationServices.WindowsF ormsApplicationBase.Run(String[] commandLine)
at WindowsApplication1.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.Run UsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context( Object state)
at System.Threading.ExecutionContext.RunInternal(Exec utionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionCon text executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionCon text executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:

View attachment 137895

Is there an easy way to understand how the C++ program is connecting when no IP Has been passed??

Any help is very much appreciated.

Regards

Stu
 

passel

Sinecure devotee
Joined
Aug 15, 2013
Messages
5,882
Re: C++ convert to VB.Net

The C++ code you are showing is the server Side of a TCP connection.
It is waiting for a client to connect to it.
When a client connects, it kicks off a thread with a new socket to accept the connection.
The client sends (to this server) the contents of a png image with the header prepended, or sent first before the image data.
The code reads the 68 byte header first, pulls the byte length of the png image from that,
allocates a buffer of that amount, then reads the remaining bytes from the stream to fill that buffer.
It then writes the buffer to a file and exits the thread once the file is written.

The VB code you've written looks like it is trying to be the Client side of the connection.
The error you are getting usually means there is no server running on that machine listening for a TCP connection at that port.

If you are suppose to replacing the C++ code, then that would be true, because you are suppose to be the server, accepting connection requests, and reading the message stream sent to you and writing the file to the disk.
 
Last edited:

stulish

New member
Joined
May 12, 2016
Messages
13
Re: C++ convert to VB.Net

Thanks PAssel,

I thought the C++ was the Client and that i would be the client, so i will no try creating a server program and see what happens, i will let you know.

Thanks

Stu
 

passel

Sinecure devotee
Joined
Aug 15, 2013
Messages
5,882
Re: C++ convert to VB.Net

I don't have the time to implement what the C++ is doing, although I don't think it would be hard for me to try if I had the time. I could probably explain the various pieces of the code, again if I had the time.

I did have an application that received an image and displayed it (to test my client side code that sent images), but it doesn't do what the C++ code does (which should be done, i.e. launch another socket in a thread to do the actual accept and connection with).
It just accepts the connection on the same socket it was listening for a connection on and receives the image, then goes back to listening for another connection. Doing it the way the C++ does it is the way it should be done since you can maximize throughput, with several sockets in separate background threads receiving images in parallel.
It also doesn't write a file.

But, as a basic test that I think might at least show that it is receiving a message and decoding the stream (assuming png image is sent), you could give it a try to see if it shows something.

I modified my code slightly to listen to the port you identified, and to first read the header bytes, and get the length from that (at offset 14 if my calculations are correct).

But because of how the structure may be packed, there could be 2 unused bytes between the fields
m_headerVersion and m_headerLength to align m_headerLength on a 4-byte boundary.
If you put a breakpoint on "iLen = ..." line before you send the first image, you can check the contents of the hdr() buffer to see if byte 14 has a number in it (which it looks like the data should be little endian so if m_dataLength started at 14 (least significant byte) there is a good chance it would not be 0. If it is 0, and byte 16 is not 0, then change the 14 to 16 before letting the code continue (after clearing the breakpoint, of course).

All you need to try this code is a new project with a large picturebox on it. Run the code and it should be waiting for a connection, and display an image in the picturebox if everything goes well.
Code:
Imports System.Net.Sockets
Imports System.Net
Imports System.IO

Public Class Form1
  Dim server As TcpListener
  Dim ListenThread As Threading.Thread = New Threading.Thread(AddressOf Listener)
  Dim bData() As Byte
  Dim hdr() as Byte
  Dim mstream As System.IO.MemoryStream
  Dim nStream As NetworkStream = Nothing
  Dim exiting As Boolean

  Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    exiting = True      'set the exiting flag so the background thread exits it's loop
    If nStream IsNot Nothing Then  'if we have a connection then
      nStream.Close()              '  break the connection
    End If
    server.Stop()                  'stop listening for a connection
    ListenThread.Join(1000)        'Wait for background thread to exit (but give up after a second) before finishing the close
  End Sub

  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    ListenThread.IsBackground = True
    ListenThread.Start()
  End Sub

  Private Sub Listener()
    Dim lPort As Int32 = 7096
    Dim lAddr As IPAddress = IPAddress.Any
    Dim iLen As Int32

    Do Until exiting   'Outer loop to restart listening if we loose the connection
      server = New TcpListener(lAddr, lPort)  'create a TCP server
      server.Start()
      Dim lClient As TcpClient = Nothing      'complains if not initialized outside try block
      Dim i As Int32
      Dim br As BinaryReader = Nothing        'complains if not initialized outside try block

      Try
        lClient = server.AcceptTcpClient()
        nStream = lClient.GetStream
        br = New BinaryReader(nStream)

        Do Until exiting  'Inner loop where we read the stream and display images
          hdr = br.ReadBytes(68)                           'Read the 68 byte header
          iLen = BitConverter.ToInt32(hdr, 14)             'Convert the 4 bytes at offset 14 (m_dataLength) into a 32-bit integer
          If iLen < 10000000 Then                          'Simply santity check of the value, don't expect more than 10 MB size
            bData = br.ReadBytes(iLen)                     '  Read all the image bytes into bData byte array
            If Not exiting Then                            '  Make sure the form is still there (close wasn't selected while we were waiting to read)
              If bData.Length = iLen Then                  '  Verify we got the amount of data expected (another sanity check)
                mstream = New System.IO.MemoryStream       '    Create a memory stream
                mstream.Write(bData, 0, bData.Length)      '    Write the image data to the memory stream

                Me.Invoke(Sub() UpdateDisplay())           '    Invoke UpdateDisplay on the GUI thread to read the stream into an image and display it
                mstream.Dispose()                          '    Dispose of the memory stream (now that it has been read)
                mstream = Nothing
              End If
            End If
          End If
        Loop

      Catch ex As Exception                               'If we get an exception at any point in the process (usually a connection lost or closed)
      Finally
        If br IsNot Nothing Then br.Dispose() ' clean up all objects used, we will recreate them if we want to reconnect
        If mstream IsNot Nothing Then mstream.Dispose()
        If nStream IsNot Nothing Then nStream.Dispose()
        If lClient IsNot Nothing Then lClient.Close()
      End Try

      server.Stop()                                      '  We will recreate the TCP server to start listening for a new connection
      server = Nothing                                   '  so get rid of the existing one.
    Loop                                                 'Loop back to see if we should reconnect, or exit.
  End Sub

  Private Sub UpdateDisplay()
    If Not exiting Then                               'If we are not exiting (in case this was invoked while we are in the process of closing the form)
      With PictureBox1
        If .Image IsNot Nothing Then .Image.Dispose() 'If we have an image in the picturebox, dispose of it first
        .Image = New Bitmap(mstream)                  'Create a nem image from the memorystream provided by the TCP receiver
      End With
    End If
  End Sub
End Class
p.s. Just relooking at my code (hadn't for awhile), I realize it is not setup the way I said. It doesn't go back to a Listen state after receiving an image. It was designed to accept one connection, then expects to receive images from that connection. The client was expected to be transmitting images periodically for display so the connection was a "permanent" connection, not a one shot transfer like the C++ code is set up to do.

If a client trying to connect to the socket setup to read causes an exception, that might kick it out to the listening state, and another client could connect, but there might be a chance that in your scenario, only the first client to connect would get its image shown, I don't know. Don't have time to test it, or modify it.

Actually, probably just comment out the Inner loop's control statements
'Do Until exiting 'Inner loop ....
and
'Loop

will make it a one shot and the outer loop will setup for listening again. Not sure.
 
Last edited:

stulish

New member
Joined
May 12, 2016
Messages
13
Re: C++ convert to VB.Net

Thanks passel,

I will try it out in the morning with the RADAR that should be sending an image every 15 seconds, and see what happens.

Cheers for all the help

Stu
 

stulish

New member
Joined
May 12, 2016
Messages
13
Re: C++ convert to VB.Net

Hi Passel,

I have been playing with the code you sent and pretty much immediately started receiving data due to my side of the protocol changing to server from client.

I have found some problems with what the RADAR is sending isn't quite correct to i had to fudge the header to take into account 2 extra bytes that had been added for some reason. but after all this i am now receiving images.

Thanks a lot for all your help :)

Regards

Stu :bigyello:
 

passel

Sinecure devotee
Joined
Aug 15, 2013
Messages
5,882
Re: C++ convert to VB.Net

It wasn't the two bytes that I mentioned might need to be added?
But because of how the structure may be packed, there could be 2 unused bytes between the fields
m_headerVersion and m_headerLength to align m_headerLength on a 4-byte boundary.

I guess there is another short and some chars in there, which may also cause some unused bytes to be added to the structure to maintain alignment. I didn't point them all out as possible things to look out for.

A pragma pack option could usually be applied to the structures to force no unused bytes (no aligning done), but access is less efficient in that case. These things always need to be checked when doing interfaces between different machines and/or different compilers/languages.
 
Top