Click here to Skip to main content
15,900,906 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am building 2 applications(a server & a client) where in, immediately after a client connection is accepted, the server send information present in the database through a buffer. Although the client receives the buffer, but when I am trying to access the buffer, an access violation error is shown.

I am pasting the sending and receiving logic of my code here:

sending logic:
C#
if(LOWORD(lParam)==FD_ACCEPT)
    {
        BOOL b = m_ServerSocket.Accept(*m_pClientSocket);
        if(b==FALSE)
        {
            AfxMessageBox("Unable to accept client's connection");
        }
        else
        {
            AfxMessageBox("Client Connected");
            //send the database info immediately after accepting the clients connection.....
            m_database.Open("AVIFilesDSN");   //database object connecting to DSN
            CAVIFileRecordset* pAviFileRecordset; //pointer to the derived class of CRecordset.
            pAviFileRecordset = new CAVIFileRecordset(&m_database);
            pAviFileRecordset->Open();
            pstrArray = new CStringArray;  //pointer to CStringArray
            while(!pAviFileRecordset->IsEOF())
            {
                //m_FilePath variable(CString) pointing to a field in database table(containing filepaths),
                pstrArray->Add(pAviFileRecordset->m_FilePath);
                pAviFileRecordset->MoveNext();
            }            
            pAviFileRecordset->Close();
            delete pAviFileRecordset;
            m_pClientSocket->Send((void*)pstrArray,MAX_BUFFER_SIZE);
            //delete pstrArray;
        }



receiving logic:
C#
int done;
char* pBuffer[MAX_BUFFER_SIZE];  //MAX_BUFFER_SIZE = 4096
pBuffer[MAX_BUFFER_SIZE] = new char;
CStringArray* pStrArray;
pStrArray = new CStringArray;
if(LOWORD(lParam)==FD_READ)
{
done = m_CSoc.Receive((void*)pBuffer,MAX_BUFFER_SIZE);
if(done==SOCKET_ERROR)
{
    AfxMessageBox("recv failed");
    return;
}
//receiving the database info
pStrArray = (CStringArray*)pBuffer;
nTemp1 = pStrArray->GetUpperBound();
nTemp = 0;
while(nTemp<=nTemp1)
{
         //displaying the contents of the string array on a list control
         m_FileListCtrl.InsertItem(nTemp,pStrArray->GetAt(nTemp)); //error occurring here
     nTemp++;
}
AfxMessageBox("Updated Files List");

}


Can I just pass the CStringArray pointer as the 1st argument in the Receive function. After casting the received buffer with CStringArray* I am able to see that the number of elements on the array and the number of items in the database are same. But when I am trying to show the received information on a list control, I am receiving the access violation error.
Posted
Updated 22-Apr-12 21:07pm
v2

You can't send objects using dynamically allocated memory over a network connection. You must send the data by accessing the buffers and get their actual size, receive them using a local buffer, and copy the received data to a new object.

In your case, you may allocate a buffer on the sender, copy all strings with NULL terminators to this buffer, and send it. On the receive side, extract the NULL terminated strings and append each to a CString object. However, this requires some additional code to handle the variable length or usage of a buffer that can hold all possible strings (max. number of strings multiplied by max. string length plus one).
 
Share this answer
 
Comments
stib_markc 23-Apr-12 4:27am    
I get your point. But that means I have to send the size of the buffer as well to the client. So any ideas, as how to distinguish the data received by the client? the client should know what it is receiving, right? any suggestions??
Jochen Arndt 23-Apr-12 4:46am    
The usual solution is to use a header structure containing the necessary information:
// Data header for network packets
#pragma pack(push, 1);
typedef struct
{
int nID; // optional fixed ID to identify the packet
int nItems; // number of strings
int nSize; // total size of packet including this header
} MyNetworkData_t;
#pragma pack(pop)

The sender should than allocate a LPBYTE buffer that can hold all the data and fill it:
// Calculate total size here
LPBYTE pBuf = new [nSize];
MyNetworkData_t *pHeader = (MyNetworkData_t *)pBuf;
pBuf->nID = HEADER_ID;
pBuf->nItems = pstrArray.GetCount();
pBuf->nSize = nSize;
int nOffset = sizeof(MyNetworkData_t);
for (int i = 0; i < pstrArray.GetCount(); i++)
{
strcpy(pBuf + nOfs, pstrArray[i].GetString());
nOfs += 1 + pstrArray[i].GetLength();
}

The receiver can than receive the header first and allocate an array for the strings:
MyNetworkData_t Header;
receive(&Header, sizeof(MyNetworkData_t));
// allocate buffer for strings
// receive data into buffer
stib_markc 23-Apr-12 4:29am    
Also if you can tell me why can't we send the dynamically allocated memory over network connection... thank you..
Jochen Arndt 23-Apr-12 5:02am    
You may send data from single allocated memory when accessing the memory in an allowed way:
send(pstrArray[i].GetString(), pstrArray[i].Getlength() + 1);
But you can't send data from objects which contains multiple allocated object itself like CStringArray (each element has an allocated buffer for the string member). Even when passing the address of a single CString object, sending may fail when using other castings. The CString::GetString() member (and the implicit LPCTSTR cast operator) return the address of the internal string buffer while the address of operator (&) returns the address of the CString object itself if the left side is not a pointer to characters.
stib_markc 23-Apr-12 5:54am    
ok, I got it. Thank you very much.
On the receiver side, the line

pBuffer[MAX_BUFFER_SIZE] = new char;


is wrong for two reasons: (a) It accesses the array at an invalid position (the highest index available is MAX_BUFFER_SIZE -1 ), (b) 'new char' allocates a 'char' object, which creates a memory leak and is totally unnecessary. This is not C# :-)

If you want to initialize the last cell of your buffer with a NULL character, then use

pBuffer[MAX_BUFFER_SIZE-1] = 0;


The next error is when you cast your buffer into a CStringArray:

pStrArray = (CStringArray*)pBuffer;


You will have to parse your buffer and assign the elements of your string array one-by-one. Simply casting a char* into a CStringArray* doesn't work.
 
Share this answer
 
Comments
stib_markc 23-Apr-12 3:32am    
ok, Thank you, I will try parsing the buffer and get back here...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900