Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Пересылка файлов через сокет  (Прочитано 10739 раз)
0 Пользователей и 1 Гость смотрят эту тему.
cishka
Гость
« : 01-04-2006 19:17 » 

Не получается переслать файл по сети.
Создаю поток с сокетом, передаю сокет в функцию пересылки файла и не могу определить конец файла.

теоретически должно работать так:
если в файле в стречается '0' я заменяю этот '0' на '00' в клиенте все наоборот, встретив '00' заменяю на '0'.
если встречаю '0' и следующий симовл какой, то другой это означает что достигнут конец файла. соответственно на сервере в последний байт отправляемого буффера  записываю этот '0'

вот серверная функция:

Код:

    /**********************************************************
    *
    *   Allow client to download files from server
    *
    ***********************************************************/
    ThreadSocket::sendfile(void* ptr)
    {
    SOCKET client=(SOCKET)ptr;
    char str1[]="filename:";
    char str2[]="transfering file:";
    char filename[255]={0};
    char *filebuff=new char[1024];
    char *sendbuff=new char[2048];
    int err,i;
    unsigned short int size;
    err=send(client,str1,strlen(str1),0);
    FILE *fp;
    if (err==SOCKET_ERROR)
        {
        printf("sendfile(void* ptr) error\n");
        return ERROR;
        }
    err=recv(client,filename,255,0);
    if (err==SOCKET_ERROR)
        {
        printf("sendfile(void* ptr) error\n");
        return ERROR;
        }
    err=send(client,str2,strlen(str2)+1,0);
    if (err==SOCKET_ERROR)
        {
        printf("sendfile(void* ptr) error\n");
        return ERROR;
        }

    fp=fopen(filename,"rb");
    int t=0;
    while(1)
        {
        err=fread(filebuff,1,768,fp);
        printf("%d, %d\n",err,t);
        for (i=0,t=0;i<err;i++,t++)
            {
            if (filebuff[i]=='0')
                {
                sendbuff[t]='0';
                sendbuff[t+1]='0';
                t++;
                }
            else
                {
                sendbuff[t]=filebuff[i];
                }
            }
        if (err<768) sendbuff[t]='0';

        size=t;
        send(client,sendbuff,size,0);
        memset(filebuff,0,1024);
        memset(sendbuff,0,2048);
        if (err<768) break;
        }
    fclose(fp);
        return 0;
    }




а вот мой клиент:



Код:

int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET client;
SOCKADDR_IN saddr;
int err;
FILE *fp;
err=WSAStartup(0x101,&wsaData);
saddr.sin_family=PF_INET;
saddr.sin_addr.S_un.S_addr=inet_addr("192.168.1.2");
saddr.sin_port=htons((u_int)8192);

client=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
err=connect(client,(struct sockaddr*)&saddr,sizeof(saddr));
if (err== INVALID_SOCKET) return 0;
char buff[]="Test Send...\n\n";
char buff_r[2048];
char buff_x[1024];
string str;
err=1;
unsigned short int size;
while(err!=-1)
{
err=recv(client,buff_r,1024,0);
printf("%s\n",buff_r);
int i,t,k=0;
char sizex[2];
if (strcmp(buff_r,"transfering file:")==0)
    {
        fp=fopen("file","wb");
        err=512;
        while(err>0)
        {
        err=recv(client,buff_r,512,0);
        for (i=0,t=0;i<err;i++,t++)
            {
            if (buff_r[i]=='0')
                if (buff_r[i+1]!='0') {err=-1;break;}
                else i++;
            buff_x[t]=buff_r[i];
            putchar(buff_x[t]);
            }
            fwrite(buff_x,t,1,fp);
            if (err==-1) break;
        }
        fclose(fp);
    }
cin >> str;
if (str=="exit") return 0;
err=send(client,str.c_str(),strlen(str.c_str())+1,0);
}
getch();
closesocket(client);
    return 0;
}


Как еще можно отсылать файлы через сокет ?
уже неделю мучаюсь Жаль возился возился файл вроди иногда и приходит но неполучается так что бы точно байт в байт все соответствовало....

еще вижу такую ситуацию... например я получил буффер....
ищу в нем значение заканчивающеся '0' и не '0' предположим достигнут на этом месте где стоит '0' должно быть продолжение в след куске буффера принятым следующим recv. как можно решить эту задачу ?
« Последнее редактирование: 14-12-2007 17:44 от Алексей1153++ » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 01-04-2006 21:09 » 

лучше не так сделать: передавай первые 4 байта - DWORD размер файла (то есть количества байт, которые прилетят следом сразу же) , следом - файл.

Если большой файл не удаётся так передать - разбивай на куски, а в приёмнике складывай взад. Улыбаюсь

такая вот имха.
Записан

cishka
Гость
« Ответ #2 : 02-04-2006 09:57 » 

над таким вариантом я думал....

но тогда возникает другая проблема.... например если я одновременно с пересылкой файла хочу слать какие нибудь команды серверу. допустим ввежду спецсимвол '1' между двумя такими символами будет находиься команда. опять таки неполучается придумать способ отследить команду если она например вдруг одна часть попадает в конец буффера а другая приходит в след раз в начало.
« Последнее редактирование: 14-12-2007 17:45 от Алексей1153++ » Записан
Михалыч
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 02-04-2006 11:35 » 

Не бывает ничего одновременного Улыбаюсь (за исключением параллельной работы в SMP системах)... Сервер-то какой - на одного клиента рассчитанный? Как сервер напишешь - так и будет. Сделай не просто 4 байта - а структуру, например. И в ней уже кодируй команды, в том числе и пересылку файла (как одну из команд), и одно из полей структуры - его размер. Короче - кто мешает разработать свой "ма-а-а-ленький" протокольчик пользовательского уровня? Сидит себе твой сервер - и только и делает, что ждет прихода структуры известного размера. Пришла - посмотрел в нее, и решил чего дальше делать - файл принимать, или команду выполнять. Простой параллельный TCP сервер - классика. Ничего особенного Улыбаюсь Можно сразу разделить функции - один клиент перекачкой файлов занимается, другой еще чем...
Можно еще, конечно использовать out of band data - но это на любителя Улыбаюсь
« Последнее редактирование: 02-04-2006 11:38 от Михалыч » Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
cishka
Гость
« Ответ #4 : 04-04-2006 14:10 » 

я как раз и пытаюсь сделать маааленький протокольчик Улыбаюсь Сервер параллельный (в том смысле что выделяет на каждого клиента отдельный поток.). только реализовывать протокол я стал подругому.. в виде обработки команд текстовых.
в цикле кручу вот такой код:
Код:
            err=recv(client,buff_r,1024,0);
            if (err==SOCKET_ERROR)
                {
                return ERROR;
                }
            switch(CommandShell((void*)buff_r))
                {
                case -1: // Нет такой команды
                    err=send(client,s2,strlen(s2)+1,0);
                    if (err==SOCKET_ERROR)
                        {
                        return ERROR;
                        }
                    printf("error!\n");
                    break;
                case 2:
                    err=sendfile((void*)client);
                    if (err!=0)
                        {
                        printf("sendfile((void*) ptr) error\n");
                        return ERROR;
                        }
                    break;
                case 3:
                            ...

                }

на данный момент мой код выглядит так
функция которя шлет файл:
Код:

    /**********************************************************
    *
    *   Allow client to download files from server
    *
    ***********************************************************/
    ThreadSocket::sendfile(void* ptr)
    {
    SOCKET client=(SOCKET)ptr;
    char str1[]="filename:";
    char str2[]="transfering file:";
    char filename[255]={0};
    char *filebuff=new char[1024];
    char *sendbuff=new char[2048];
    int err,i;
    unsigned short int size;
    err=send(client,str1,strlen(str1),0);
    FILE *fp;
    if (err==SOCKET_ERROR)
        {
        printf("sendfile(void* ptr) error\n");
        return ERROR;
        }
    err=recv(client,filename,255,0);
    if (err==SOCKET_ERROR)
        {
        printf("sendfile(void* ptr) error\n");
        return ERROR;
        }
    err=send(client,str2,strlen(str2)+1,0);
    if (err==SOCKET_ERROR)
        {
        printf("sendfile(void* ptr) error\n");
        return ERROR;
        }

    fp=fopen(filename,"rb");
    int t=0;
    while(1)
        {
        err=fread(filebuff,1,768,fp);
        for (i=0,t=0;i<err;i++,t++)
            {
            if (filebuff[i]=='0')
                {
                sendbuff[t]='0';
                t++;
                sendbuff[t]='0';
                }
            else
                {
                sendbuff[t]=filebuff[i];
                }
            }
        if (err<768)    {
                        sendbuff[t]='0';
                        t++;
                        sendbuff[t]='1';
                        t++;
                        }
        size=t;
        send(client,sendbuff,size,0);
        memset(filebuff,0,1024);
        memset(sendbuff,0,2048);
        if (err<768) break;
        }
    fclose(fp);
        return 0;
    }

клиент:
Код:
#include "winsock2.h"
#include "windows.h"
#include "iostream.h"
#include "conio.h"

int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET client;
SOCKADDR_IN saddr;
int err;
FILE *fp;
err=WSAStartup(0x101,&wsaData);
saddr.sin_family=PF_INET;
saddr.sin_addr.S_un.S_addr=inet_addr("192.168.1.2");
saddr.sin_port=htons((u_int)8192);

client=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
err=connect(client,(struct sockaddr*)&saddr,sizeof(saddr));
if (err== INVALID_SOCKET) return 0;
char buff[]="Test Send...\n\n";
char buff_r[1024*64];
char buff_x[1024*64];
string str;
err=1;
unsigned short int size;
while(err!=-1)
{
err=recv(client,buff_r,1024,0);
printf("%s\n",buff_r);
int i,t,k=0;
char sizex[2];
if (strcmp(buff_r,"transfering file:")==0)
    {
        fp=fopen("file","wb");
        err=512;
        while(err>0)
        {
        for(k=0;k<1024;k++) { buff_r[k]=0; buff_x[k]=0;}
        err=recv(client,buff_r,1024*32,0);

        for (i=0,t=0;i<err;i++,t++)
            {
            if (buff_r[i]=='0' && buff_r[i+1]!='0') {err=-1;break;}
            if (buff_r[i]=='0') i++;
            buff_x[t]=buff_r[i];
            fputc(buff_x[t],fp);
            }
            if (err==-1) break;
        printf("#");
        }
        fclose(fp);
printf("\n");
    }
cin >> str;
if (str=="exit") return 0;
err=send(client,str.c_str(),strlen(str.c_str())+1,0);
}
getch();
closesocket(client);
    return 0;
}

Получилось сейчас принять файл без ошибок (Увеличив размер буффера в recv до 32кб).
а возможно как-нибудь сделать так что бы  recv заполняла буффер только до тех пор, пока не встретится определенная последовательность ? т.е. что бы я напрямую неуказывал сколько байт нужно получить ?
и еще что понимается под out of band data ? (извеняюсь за ламерский вопрос Улыбаюсь )
« Последнее редактирование: 14-12-2007 17:46 от Алексей1153++ » Записан
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 06-04-2006 14:53 » 

cishka, коль скоро зашла речь об изобретении своего "протокольчика", то, может быть, вам стоит ознакомиться с протоколом TFTP (ftp://ftp.rfc-editor.org/in-notes/std/std33.txt)

Это проверенный временем очень простой протокол передачи данных по сети.  Есть множество открытых реализаций, с которых можно срисовать себе код.  Например, навороченный сервер и клиент nTFTP http://sourceforge.net/projects/ntftp
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines