When wxSocket transmiss a file which class should i use? Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
hats
Experienced Solver
Experienced Solver
Posts: 70
Joined: Wed Sep 16, 2009 3:50 pm
Location: China
Contact:

When wxSocket transmiss a file which class should i use?

Post by hats »

I use wxSocketClient transmiss a file to wxSocketServer,when the file's length less than 8688 bytes,they work well,otherwise,wxSocketServer will read 8688 bytes at most.
So when transmiss a file which class should i use? wxSocketClient or wxSocketOutputStream/wxSocketInputStream ?
wx2.8.11
Win XP GCC 4.4.1/VC2005
Ubuntu 10.04 GCC 4.4.3
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

Please post some code; sockets are streams so have theorically no transfer limit. I thus suppose that you sending and/or reading code is incorrect
"Keyboard not detected. Press F1 to continue"
-- Windows
hats
Experienced Solver
Experienced Solver
Posts: 70
Joined: Wed Sep 16, 2009 3:50 pm
Location: China
Contact:

Post by hats »

ok! I use wxThread in wxSocketClient,when drop files on wxTextCtrl,the thread will be run.
First i write 1 byte to tell wxSocketServer that 1 is a file,and then 4 bytes to tell wxSocketServer file'size,and then 50 bytes is the file's name,and last is file data that need to be saved.
here is the code that in wxSocketClient program:

Code: Select all

void* SocketThread::Entry()
{
    /*
    his->m_arrFileName is the array that when drop files on wxTextCtrl
    */
    for(size_t i=0; i<this->m_arrFileName.GetCount(); i++)
    {
        wxString filePath = this->m_arrFileName[i];//files path
        wxString fileName = wxFileNameFromPath(filePath);//file name

        const wxChar* pName = fileName.c_str();//wxChar* file name

        wxFile file;
        file.Open(filePath,wxFile::read);
        size_t fileSize = file.Length();//file;size

        wxUint8 type = 1;//1=>file,0=>text
        wxMemoryBuffer memoryBuffer;
        memoryBuffer.AppendData(&type,1);//append type
        memoryBuffer.AppendData(&fileSize,4);//append file size
        memoryBuffer.AppendData(pName,50);//append file name
        wxUint8* buffer = new wxUint8[fileSize];
        size_t len = file.Read(buffer,fileSize);//read file data into wxMemoryBuffe
        memoryBuffer.AppendData(buffer,len);//append file data

        size_t length = memoryBuffer.GetDataLen();//data'length that need to send
        wxUint8* data = (wxUint8*)memoryBuffer.GetData();//data

        this->m_socket->Write(data,length);//Write data to wxSocketServer

        file.Close();
        delete []buffer;
    }

    return NULL;
}
When wxSocketServer receive socket event,it will start a new thread.
First it read 1 byte to know the type of socket data,and then 4 bytes to know the data length ,last is the data.
Here is the code that in wxSocketServer:

Code: Select all

void* SocketThread::Entry()
{
    wxUint8 type;//type
    this->m_socket->Read(&type,1);

    if(type == 0)//text that should show on gui
    {
        size_t length;//wxChar length
        this->m_socket->Read(&length,4);

        wxChar* buffer = new wxChar[length/2];
        this->m_socket->Read(buffer,length);
        wxString s(buffer);
        this->m_listCtrl->InsertItem(0,wxT(""));
        this->m_listCtrl->SetItem(0,0,s);
        //wxMessageBox(wxString::Format(wxT("Type: %d,Length: %d,Value: %s,Receive: %d"),type,length,s.c_str(),this->m_socket->LastCount()));
        delete []buffer;
    }
    else if(type == 1)//a file
    {
        size_t length;//wxFile length
        this->m_socket->Read(&length,4);

        wxChar* pName = new wxChar[50/2];//file'name
        this->m_socket->Read(pName,50);

        wxString fileName(pName);//wxString file name

        wxUint8* buffer = new wxUint8[length];//buffer

	    this->m_socket->Read(buffer,length);

        wxFile file;//create a new file
        file.Create(fileName,true);
        file.Open(fileName,wxFile::write);
        file.Write(buffer,this->m_socket->LastCount());
        file.Close();
        delete []buffer;
		
        /*wxMessageBox(wxString::Format(wxT("Type: %d,Length: %d,FileName: %s"),type,length,pName));*/
        delete []pName;
    }


    return NULL;
}
I use codeblocks wx2.8.11 unicode multi gcc dll .the project is in attachment.
Attachments
wxSocket.zip
(71.68 KiB) Downloaded 108 times
wx2.8.11
Win XP GCC 4.4.1/VC2005
Ubuntu 10.04 GCC 4.4.3
briceandre
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 672
Joined: Tue Aug 31, 2010 6:22 am
Location: Belgium

Post by briceandre »

Either you configure your socket in blocking mode (http://biolpc22.york.ac.uk/wx/docs/html ... sesetflags) or you should write a more complex code.

Your problem is that you fills the output buffer and the socket truncates the sent data. If you want to send everyting with a single command, you should configure your socket in blocking mode. But, in this case, the GUI will be blocked until everything is sent.

If you do not want the GUI to be blocked, you have to check how many bytes were sent (with wxSocketBase::LastCount) and send remaining data when there is space in output buffer.
hats
Experienced Solver
Experienced Solver
Posts: 70
Joined: Wed Sep 16, 2009 3:50 pm
Location: China
Contact:

Post by hats »

I use wxSoketClient::SetFlags(wxSOCKET_BLOCK) and wxSocketServer::SetFlags(wxSOCKET_BLOCK) before read.
but result is the same.
wx2.8.11
Win XP GCC 4.4.1/VC2005
Ubuntu 10.04 GCC 4.4.3
briceandre
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 672
Joined: Tue Aug 31, 2010 6:22 am
Location: Belgium

Post by briceandre »

Do you provide wxSOCKET_WAITALL flag also ?
hats
Experienced Solver
Experienced Solver
Posts: 70
Joined: Wed Sep 16, 2009 3:50 pm
Location: China
Contact:

Post by hats »

Yes.but still the same result.
On wxSocketServer program, when it read bytes less than 8000 each time,the project work well.
wx2.8.11
Win XP GCC 4.4.1/VC2005
Ubuntu 10.04 GCC 4.4.3
Danny Scott
In need of some credit
In need of some credit
Posts: 1
Joined: Thu Jan 13, 2011 4:42 pm

Post by Danny Scott »

There is no guaranty that all of the data will show up at the same time.

You should be checking LastCount after every read to ensure that you actually did read some data.

In your type==1 condition you should do something like the following in place of

// this->m_socket->Read(buffer,length);

wxUint32 u32Rcvd = 0;

while (u32Rcvd < length)
{
this->m_socket->Read(buffer + u32Rcvd,length - u32Rcvd);
u32Rcvd += this->m_socket->LastCount();
// Maybe check for error here with this->m_socket->Error and LastError
// Maybe sleep a bit here to take load off cpu.
}

Hope this helps.
Danny Scott
Post Reply