Page 1 of 1

When wxSocket transmiss a file which class should i use?

Posted: Thu Jan 06, 2011 1:14 pm
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 ?

Posted: Thu Jan 06, 2011 4:23 pm
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

Posted: Fri Jan 07, 2011 11:48 am
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.

Posted: Fri Jan 07, 2011 2:30 pm
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.

Posted: Sat Jan 08, 2011 4:04 pm
by hats
I use wxSoketClient::SetFlags(wxSOCKET_BLOCK) and wxSocketServer::SetFlags(wxSOCKET_BLOCK) before read.
but result is the same.

Posted: Sat Jan 08, 2011 10:23 pm
by briceandre
Do you provide wxSOCKET_WAITALL flag also ?

Posted: Wed Jan 12, 2011 1:20 am
by hats
Yes.but still the same result.
On wxSocketServer program, when it read bytes less than 8000 each time,the project work well.

Posted: Thu Jan 13, 2011 5:10 pm
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.