Builder + WinAPI send recv select ...
От: ynblpb  
Дата: 18.02.03 19:09
Оценка:
Писал клиент-сереврную моногопоточную программу под Builder используя API функции send recv select accept. Суть программы — передача файлов по сети от клиента к серверу разбивая их на части определенного размера, также в пакет перед send вставляю в заголовок свою структуру данных, а далее собственно данные пакета. Все работает если: клиент и сервер запускаются на локалхосте (файлы передаются нормально), так же работает в паре машин c XP+98 сервер и клиент попеременно запускался на разных машинах файлы передаюся, НО пробовал тестить работу на паре машин XP+XP в ходе пересылки данных сервер после захода в send не возвращает управление в поток. Подскажите в чем может быть проблема
можть и я вам когда-нибудь помогу
Re: Builder + WinAPI send recv select ...
От: VVV Россия  
Дата: 19.02.03 20:16
Оценка:
Здравствуйте, ynblpb, Вы писали:

Y>Писал клиент-сереврную моногопоточную программу под Builder используя API функции send recv select accept. Суть программы — передача файлов по сети от клиента к серверу разбивая их на части определенного размера, также в пакет перед send вставляю в заголовок свою структуру данных, а далее собственно данные пакета. Все работает если: клиент и сервер запускаются на локалхосте (файлы передаются нормально), так же работает в паре машин c XP+98 сервер и клиент попеременно запускался на разных машинах файлы передаюся, НО пробовал тестить работу на паре машин XP+XP в ходе пересылки данных сервер после захода в send не возвращает управление в поток. Подскажите в чем может быть проблема


У нас есть такая часть — передача по сокетам; попросил специально тестеров проверить вариант XP+Xp — всё работает, без проблем. Компиллер Borland BC 5.02 без OWL, просто сокетный интерфейс: чистый send recv select accept. Если приведёшь кусок кода, будет проще найти проблему.
Re[2]: Builder + WinAPI send recv select ...
От: Аноним  
Дата: 20.02.03 06:53
Оценка:
Здравствуйте, VVV, Вы писали:

// Главный юнит.
void __fastcall TForm1::GetFileClick(TObject *Sender)
{
        TCPThread *mth=new TCPThread(false,FilStr->Text);
        mth->FreeOnTerminate=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
        WSADATA    wData;
    WORD    mVer;
    int    err;

    mVer= MAKEWORD(2,2);
    err=WSAStartup(mVer,&wData);

}



// Юнит потока клиента.
// FILE,TRANSMISSION,END_OF_TRANSMISSION - Дефайны
//s определен в хедере
 
__fastcall TCPThread::TCPThread(bool CreateSuspended,AnsiString FilName)
        : TThread(CreateSuspended)
{
        FileName=FilName;
}
//---------------------------------------------------------------------------
void __fastcall TCPThread::Execute()
{
        int hFile;
        PckHd PacketHead;
    int tmp,iByteRecv,cnt=2048;
    WORD port;
        AnsiString FullFileName,FLen,Abuff,ShortFileName;
        char *buff;
        bool flag=false;
        int iFileLength;
        int iBytesRead,err;
    fd_set rdfds;
    TIMEVAL tm;

    FD_ZERO(&rdfds);

    tm.tv_sec=0;
    tm.tv_usec=0;

        unsigned long adlo;
        BytesRec=0;

    port=6666;

        adlo=inet_addr("127.0.0.1");//Или любой адрес где стоит сервер

        sockaddr_in adr;
    adr.sin_addr.S_un.S_addr=adlo;
    adr.sin_family=AF_INET;
    adr.sin_port=htons(port);

        ShortFileName=FileName;
        int i=ShortFileName.Length();
        while(flag!=true)
        {
                if(ShortFileName.c_str()[i]=='\\')
                {
                        ShortFileName=ShortFileName.Delete(1,i+1);
                        flag=true;
                }
                else
                i--;
        };
        flag=false;

        s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

          FD_SET(s,&rdfds);

    tmp=connect(s,(sockaddr*)&adr,sizeof(sockaddr_in));
        if(tmp==0)
        {
                PacketHead.CurrPacketSize=FileName.Length()+1;
                PacketHead.Head=FILE;

                buff=(char*)malloc(sizeof(PckHd)+PacketHead.CurrPacketSize);

                memcpy(buff,&PacketHead,sizeof(PckHd));
                memcpy(buff+sizeof(PckHd),FileName.c_str(),PacketHead.CurrPacketSize);

                send(s,buff,sizeof(PckHd)+PacketHead.CurrPacketSize,0);

                free(buff);
                buff=(char*)malloc(sizeof(PckHd)+2048);

                AnsiString Path;
                Path="c:\\"+ShortFileName;//Любой путь куда копировать
                hFile=FileCreate(Path);
                while(flag!=true)
                {
                           if(select(0,&rdfds,NULL,NULL,NULL)>0)//&tm
                        {
                                iByteRecv=recv(s,buff,sizeof(PckHd)+cnt,MSG_PEEK);
                                if(((PckHd*)buff)->Head==TRANSMISSION)
                                {
                                        realloc(buff,sizeof(PckHd)+((PckHd*)buff)->CurrPacketSize);
                                        err=recv(s,buff,sizeof(PckHd)+((PckHd*)buff)->CurrPacketSize,0);
                                        err=FileWrite(hFile,(char*)buff+sizeof(PckHd),((PckHd*)buff)->CurrPacketSize);
                                        BytesRec+=err;
                                        Synchronize(ChangeCap);
                                }
                                else
                                {
                                        if(((PckHd*)buff)->Head==URL)
                                        {
                                                realloc(buff,sizeof(PckHd)+((PckHd*)buff)->CurrPacketSize);
                                                recv(s,buff,sizeof(buff),0);
                                                err=FileWrite(hFile,(char*)buff+sizeof(PckHd),((PckHd*)buff)->CurrPacketSize);
                                                BytesRec+=err;
                                                Synchronize(ChangeCap);
                                        };
                                        if(((PckHd*)buff)->Head==END_OF_TRANSMISSION)
                                        {
                                                realloc(buff,sizeof(PckHd)+((PckHd*)buff)->CurrPacketSize);
                                                recv(s,buff,sizeof(buff),0);
                                                err=FileWrite(hFile,(char*)buff+sizeof(PckHd),((PckHd*)buff)->CurrPacketSize);
                                                BytesRec+=err;
                                                Synchronize(ChangeCap);
                                                FileClose(hFile);
                                                flag=true;
                                        };
                                };
                        };
                };
        };
        closesocket(s);
}
//---------------------------------------------------------------------------
void __fastcall TCPThread::ChangeCap()
{
        Form1->ByRec->Caption=IntToStr(BytesRec);
}


это то что в клиенте в главном и юните потока.

//Главный юнит сервера

void __fastcall TForm1::FormCreate(TObject *Sender)
{
        AccTime->Enabled;
        MsgHst->Clear();
    WSADATA    wData;
    WORD    mVer;
    int    err;
    int     tmp;
    WORD port;

    port=6666;
    mVer= MAKEWORD(2,2);
        sockaddr_in adr;
    adr.sin_addr.S_un.S_addr=INADDR_ANY;
    adr.sin_family=AF_INET;
    adr.sin_port=htons(port);

    err=WSAStartup(mVer,&wData);
    s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    tmp=bind(s,(sockaddr*)&adr,sizeof(sockaddr_in));
    err=listen(s,1);
}
//-------------------------------
void __fastcall TForm1::AccTimeTimer(TObject *Sender)
{
        SOCKET rSock;
    fd_set rdfds;
    TIMEVAL tm;

    FD_ZERO(&rdfds);
    FD_SET(s,&rdfds);

    tm.tv_sec=0;
    tm.tv_usec=0;

    if(select(0,&rdfds,NULL,NULL,&tm)>0)
        {
                sockaddr nadr;
                int dl=sizeof(sockaddr);
                rSock=accept(s,(sockaddr*)&nadr,&dl);//?!sockaddr
                if(rSock!=INVALID_SOCKET)
                {
                        TCPThread *mth = new TCPThread(false,rSock);
                        mth->FreeOnTerminate = true;
                }
        };
}



//Юнит потока процесса sock определен в хедере
__fastcall TCPThread::TCPThread(bool CreateSuspended,SOCKET s)
        : TThread(CreateSuspended)
{
        sock=s;
}
//---------------------------------------------------------------------------
void __fastcall TCPThread::Execute()
{
        bool flag=false;

        PckHd   PacketHead;

        AnsiString  tmpstr;
        int UrlLen;
        int iFileHandle,iByteRecv;
        HANDLE hFile;
        LPVOID hView,pStart;
        int cnt,pOff=0;
        DWORD dwSizeLow,dwSizeHigh;

    int    err;
    int tmp;
    WORD port;

        unsigned long adlo;

    port=6666;

    fd_set rdfds;
    TIMEVAL tm;

    FD_ZERO(&rdfds);
    FD_SET(sock,&rdfds);

    tm.tv_sec=0;
    tm.tv_usec=0;

        UrlName="";FileName="";
        char *buff;
        cnt=2048;
        buff=(char*)malloc(sizeof(PckHd)+cnt);

        while(flag!=true)
        {
                if(select(0,&rdfds,NULL,NULL,&tm)>0)
                {
                        iByteRecv=recv(sock,buff,sizeof(PckHd)+cnt,MSG_PEEK);
                        if(((PckHd*)buff)->Head==FILE)
                        {
                                realloc(buff,sizeof(PckHd)+((PckHd*)buff)->CurrPacketSize);
                                err=recv(sock,buff,sizeof(buff),0);
                                FileName=(char*)buff+sizeof(PckHd);
                                Stat="FileNameRecived: "+FileName;
                                Synchronize(ChangeCap);
                                flag=true;
                        }
                        else
                        {
                                if(((PckHd*)buff)->Head==URL)
                                {
                                        realloc(buff,sizeof(PckHd)+((PckHd*)buff)->CurrPacketSize);
                                        err=recv(sock,buff,sizeof(buff),0);
                                        UrlName=(char*)buff+sizeof(PckHd);
                                        flag=true;
                                };
                        };
                };
        };

        free (buff);

        if(FileName!="")
        {
                iFileHandle = FileOpen(FileName, fmOpenRead);
                dwSizeLow = GetFileSize((HANDLE)iFileHandle, &dwSizeHigh);
                hFile=CreateFileMapping((HANDLE)iFileHandle,NULL,PAGE_READONLY,dwSizeHigh,dwSizeLow,NULL);
                hView=MapViewOfFile(hFile,FILE_MAP_READ,0,0,dwSizeLow);
                Stat="FileMappingSucceed! FileSize: "+IntToStr(dwSizeLow);
                Synchronize(ChangeCap);
                pStart=hView;

                buff=(char*)malloc(sizeof(PckHd)+cnt);

                if(dwSizeLow>2048) cnt=2048;
                else
                {
                        PacketHead.Head=END_OF_TRANSMISSION;
                        PacketHead.CurrPacketSize=dwSizeLow;
                        realloc(buff,sizeof(PckHd)+dwSizeLow);
                        memcpy(buff,&PacketHead,sizeof(PckHd));
                        memcpy(buff+sizeof(PckHd),pStart,dwSizeLow);
                        err=send(sock,buff,sizeof(PckHd)+dwSizeLow,0);
                        BytesSend+=err;
                        Stat="BytesSending...";
                        Synchronize(ChangeCap);
                        flag=false;
                };

                while(flag!=false)
                {
                        if(cnt+pOff<dwSizeLow)
                        {
                                PacketHead.Head=TRANSMISSION;
                                PacketHead.CurrPacketSize=cnt;
                                memcpy(buff,&PacketHead,sizeof(PckHd));
                                memcpy(buff+sizeof(PckHd),(char*)pStart+pOff,cnt);
                                err=send(sock,buff,sizeof(PckHd)+cnt,0);
                                BytesSend+=err;
                                Stat="BytesSending...";
                                Synchronize(ChangeCap);
                                pOff+=cnt;
                        }
                        else
                        {
                                cnt=dwSizeLow-pOff;
                                PacketHead.Head=END_OF_TRANSMISSION;
                                PacketHead.CurrPacketSize=cnt;
                                realloc(buff,sizeof(PckHd)+cnt);
                                memcpy(buff,&PacketHead,sizeof(PckHd));
                                memcpy(buff+sizeof(PckHd),(char*)pStart+pOff,cnt);
                                err=send(sock,buff,sizeof(PckHd)+cnt,0);
                                BytesSend+=err;
                                Stat="BytesSending...";
                                Synchronize(ChangeCap);
                                flag=false;
                        };
                };
                UnmapViewOfFile(hView);
                Stat="Unmaping Success!!!";
                Synchronize(ChangeCap);
        };

}
//---------------------------------------------------------------------------
void __fastcall TCPThread::ChangeCap()
{
        Form1->BySend->Caption=IntToStr(BytesSend);
        Form1->Status->Caption=Stat;
}




Вот собственно и все. Мне кажется это не из-за bind т.к. на XP+98 все работает корректно. А в XP+XP (правда только в тесте участвовали 3 машины XP) может преслать либо некоторое кол-во байт а потом зайти в send и от туда не выйти, может вообще не переслать, а случалось и пересылал весь файл.

ЗЫ: Такое чуйство что в send`е идет блок. Компилятор C++ Builder 6
ЗЗЫ: ПЛЗ!!! =)) Не могли бы вы отправить мне на мыло ваш пример просто из спортивного интереса =) ynblpb@hotbox.ru или ynblpb@freemail.ru
можть и я вам когда-нибудь помогу
Re[3]: Builder + WinAPI send recv select ...
От: VVV Россия  
Дата: 20.02.03 15:53
Оценка:
Здравствуйте, Аноним, Вы писали:

..
А>Вот собственно и все. Мне кажется это не из-за bind т.к. на XP+98 все работает корректно. А в XP+XP (правда только в тесте участвовали 3 машины XP) может преслать либо некоторое кол-во байт а потом зайти в send и от туда не выйти, может вообще не переслать, а случалось и пересылал весь файл.

А>ЗЫ: Такое чуйство что в send`е идет блок. Компилятор C++ Builder 6

А>ЗЗЫ: ПЛЗ!!! =)) Не могли бы вы отправить мне на мыло ваш пример просто из спортивного интереса =) ynblpb@hotbox.ru или ynblpb@freemail.ru
А>можть и я вам когда-нибудь помогу
А>

1. Думается, это может происходить из-за того, что recv может возвращать не все запрошенные данные, а по частям (также и send) — пример: послали строку "Вперёд, комсомол!", а получаем так: "Вперёд" ", " "комсо" "мол!", т.е. за четыре вызова recv. Т.е. нужен цикл, пока всё не считаем. Примеров не нашёл, есть код из проекта:
long
TSockHelper::Recv(SOCKET sock, void *Buf_, int iSize, int iTimeout)
{
  TIMEVAL TheTime={1, 0};
  int err;
  int rc;
  fd_set readfds;
  fd_set exceptfds;
  FD_ZERO(&readfds);
  FD_ZERO(&exceptfds);
  int iShift=0;
  char *Buf=(char*)Buf_;

  while(iSize > 0)
   {
    FD_SET(sock, &readfds);
    FD_SET(sock, &exceptfds);

    err=::select(0, &readfds, 0, &exceptfds, &TheTime);

    if(err == SOCKET_ERROR || FD_ISSET(sock, &exceptfds))
      return SOCKET_ERROR;

    if(FD_ISSET(sock, &readfds))
     {
      rc=::recv(sock, Buf+iShift, iSize, 0);
      if(rc == SOCKET_ERROR)
        return SOCKET_ERROR;
      iShift+=rc;
      iSize-=rc;
    }
    else
    if(err == 0)
     {
      if(iTimeout < 0 && --iTimeout == 0)
        return SOCKET_ERROR;
    }
  }

  return iShift;
}

//вызов
struct MyData{
...
};

MyData data;
TSockHelper::Recv(sock, &data, sizeof(data), 10); //10 seconds timeout


аналогично и для send написана Send.

2. Потенциальные ошибки:
из п.1 следует, что здесь в buff могло ещё не приняться sizeof(PckHd) байт, поэтому ((PckHd*)buff)->CurrPacketSize) вернёт неверное значение:
         realloc(buff,sizeof(PckHd)+((PckHd*)buff)->CurrPacketSize);
         recv(s,buff,sizeof(buff),0);

функция realloc переразмещает буфер,

The size argument gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Because the new block can be in a new memory location, the pointer returned by realloc is not guaranteed to be the pointer passed through the memblock argument.

поэтому верное использование такое:
         buff=realloc(buff,sizeof(PckHd)+((PckHd*)buff)->CurrPacketSize);


2.1 recv(s,buff,sizeof(buff),0); — как думаешь чему равно sizeof(buff)? правильно — всего 4 байта (32 бита) под Win32, поэтому здесь принимаешь максимум 4 байта. Думаю, ты хотел написать примерно следующее:
         int rc=recv(s, buff+sizeof(PckHd), ((PckHd*)buff)->CurrPacketSize,0);

написал buff+sizeof(PckHd), потому что заголовок-то уже получен (хотя, может, не совсем понял протокола — не настаиваю )

2.2. err=FileWrite(hFile,(char*)buff+sizeof(PckHd),((PckHd*)buff)->CurrPacketSize);
соответственно и в файл писать надо, то количество байт, которое вернул recv.

Код посмотрел не полностью (большой больно). Но, думаю, что и так чуть-чуть поможет .
Re[4]: Builder + WinAPI send recv select ...
От: ynblpb  
Дата: 20.02.03 17:01
Оценка:
Здравствуйте, VVV, Вы писали:

Просто в чем дело то было. Поставил я синхронизированное ShowMessage после сенда и оно не вызвалось что сказало о том что из send`a не вернулось управление. т.е. я не могу даже ошибку посмотреть сенда т.к. программа дальше не идет.
можть и я вам когда-нибудь помогу
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.