На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
    > Передача файлов по сети , с использованием сокетов и чистого WinAPI
      Прошу привести простой пример передачи файлов между клиентом и сервером, используя сокеты и чистый WinAPI (не используя MFC). Пример должен быть консольной прогой.

      Спасибо.
        как это не банально, но совет будет такой: лучше прочитай книжку по сетевому программированию. там все подробно разложено и рассказано. учиться программировать сетевое приложение в форуме - это очень ненадежно, так как у тебя так и не появится четкого понимания, а знания ты будешь вырывать кусками.

        Цитата
        лучше потратить неделю, а потом за пять минут долететь...
          Совет хороший дал bugger.
          У меня есть пара минут свободных, поэтому покажу простой пример.
          Ну прежде всего johen тебе надо определиться с протоколом (протоколом уровня приложений если по научному), мне кажется не стоит чего-то там своего изобретать, типа придумывать свои ключевые слова или байты, а стоит воспользоваться HTTP или FTP протоколом.

          Когда-то смотрел, что там IExplorer посылает, получилась такая консольная програмка:
          ExpandedWrap disabled
            #include "stdafx.h"
            #include <winsock.h>
            #include <stdio.h>
            #include <iostream.h>
             
             
                WSADATA wsa;        
                SOCKET sock, sock2;
                
                struct sockaddr_in peer;
                struct sockaddr_in accp;
             
                unsigned accp_len =sizeof(accp);
                
                int k,net,size,len;
                int headlen,bodylen;
                int port = 80 ;
             
                char * pbuf,* pbuf2;
                char sbuf[204800]="\0";
                char Buf[200480]="\0";
                char sbuf1[256]="\0";
                char sbuf2[256]="\0";
                char answ[512]="\0";
             
                FILE *hd;
                BOOL HEADER=FALSE;
             
             
            int main(int argc, char* argv[])
            {
             
                printf("\n $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
                printf(" $\t\t\t\t\t\t\t\t        $\n");
                printf(" $\t\t\t\t\t\t\t\t        $\n");    
                printf(" $\t      Simple Web Server by Elektrik (ICQ:262102)  \t        $\n");  
                printf(" $\t\t\t\t\t\t\t\t        $\n");
                printf(" $\t\t\t\t\t\t\t\t        $\n");        
                printf(" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n");
             
                printf("\n port: ");
                memset(sbuf,'\0',sizeof(sbuf));
                gets(sbuf);
                for(int i=0;i<strlen(sbuf);i++)
                {
                    if (!isdigit(sbuf[i]))
                    {
                        printf("\n  port: not correct\n");
                        return 1;
                    }
                }
                port=atoi(sbuf);
                if(port==0) port=80;
             
             
            while(1)
            {
                
                WSAStartup(MAKEWORD(1,1),&wsa);
             
                sock = socket(AF_INET,SOCK_STREAM,0);
             
                if ( sock == INVALID_SOCKET)
                {
                    printf(" Cannot bild server\n");
                    return 1;
                }
                
                peer.sin_family = AF_INET;
                peer.sin_port = htons(port);
                peer.sin_addr.s_addr = htonl(INADDR_ANY);
             
                net = bind(sock,(struct sockaddr *)&peer,sizeof(peer));
             
                if ( net!=0)
                {
                    printf(" Cannot bild server with such port\n");
                    return 1;
                }
                
                printf(" Server started [port==%d] .....",port);
                
                listen(sock,0);
             
                printf(" waiting for qwery\n");
             
                sock2=accept(sock,(struct sockaddr *) &accp,(int *) &accp_len);
             
                if (sock2==-1)
                {
                    printf("\n accept==-1\n");
                    return 1;
                }
             
                memset(sbuf,'\0',sizeof(sbuf));
                memset(Buf,'\0',sizeof(Buf));
             
                hd=fopen("c:\\1.txt","at");
                
                for(net=0,len=0,bodylen=0;net!=SOCKET_ERROR;)
                {
                    cout << endl << " recv: ";      
             
                    net = recv(sock2,sbuf,sizeof(sbuf),0);
                            
                    if(net==SOCKET_ERROR)
                    {
                        printf("\n recv == -1\n");
                        return 1;
                    }
                    
                    cout << net << endl << endl;
             
                    if (net==0) goto _SEND_;
                    
                    fwrite(sbuf,1,net,hd);
                    strncat(Buf,sbuf,net);
                    printf("%s",sbuf);  
             
            // \r == 13(OxD) \n == 10(0xA)  
            // 13 10 13 10
             
                    if(!HEADER)
                    {          
                        for(int i=0;i<strlen(Buf);i++)      
                        {
                            if( // Точка границы заголовка и тела ответа
                                
                                Buf[i]   == 10  &&
                                Buf[i-1] == 13  &&
                                Buf[i-2] == 10  &&
                                Buf[i-3] == 13
             
                                ) // Заголовок принят, обрабатываем
                            {
                                i++;       // учитываем ноль
                                headlen=i; // Длина заголовка
             
                                if(strstr(Buf,"GET")) goto _SEND_; // Всё приняли, иначе POST
                                
                                if(strstr(Buf,"POST"))
                                {
                                    if(Buf[i]!=0) len=strlen(Buf+i); // Сколько приняли байт из тела, если POST
                                                            
                                    printf("\n bodylen: ");
             
                                    pbuf=strstr(Buf,"Content-Length:");
                                    if(pbuf)
                                    {              
                                        sscanf(pbuf,"%s%s",sbuf1,sbuf2);
                                                                
                                        bodylen=atol(sbuf2); // Длина тела
                                                                
                                        printf("%d\n\n",bodylen);                          
                                    }
                                
                                }              
             
                                HEADER=TRUE; // Заголовок обработан
                                break;
                            }
                        }
                    }
             
             
             
                    if(HEADER) // Заголовок обработан
                    {      
             
                        len+=net; // Сколько приняли байт из тела
                        if(len>=bodylen) // Приняли всё, посылаем ответ
                        {
             
            _SEND_:            
                            strcpy(answ,"HTTP/1.1 200 OK\r\n");
                            strcat(answ,"Server: My\r\n");      
                            strcat(answ,"Connection: close\r\n");
                            strcat(answ,"Content-Type: text/html\r\n\r\n");
                            strcat(answ,"<html><body>\n<script language=\"JavaScript\">\nwindow.status = \"_ok_\";\n</script>\n</body></html>");
             
                            for(net=0,k=0,len=strlen(answ);net!=SOCKET_ERROR;)
                            {
             
                                cout << endl << endl << "\n\n send: ";
                                
                                net=send(sock2,(char*)(answ+k),len-k,0);
             
                                cout << net << endl << endl;
             
                                memset(Buf,'\0',sizeof(Buf));
                                strncpy(Buf,answ+k,net);
                                printf("%s",Buf);
             
                                k+=net;                
             
                                if(net==SOCKET_ERROR)
                                {
                                    printf(" send == -1\n");
                                    return 1;
                                }                                  
             
                                if(k>=len) // Отослали всё
                                {
                                    printf("\n\n answer was sending\n");
                                    break;
                                }
                            }          
                            break;
                        }
                    }      
                    
                }  
                
                fclose(hd);
             
                if(sock) closesocket(sock);
                if(sock2) closesocket(sock2);
             
                WSACleanup();
             
                printf("\n\n server closed\n");
             
                
            }
                printf(" end\n");
                return 0;
            }

          Только при посылке файла(сначала отсылаешь текстовый заголовок, потом открываешь файл в бинарном виде и отсылаешь) будь аккуратен с текстовыми функциями.
          Например у меня здесь строку if(Buf[i]!=0) len=strlen(Buf+i); // Сколько приняли байт из тела, если POST
          надо убирать.

          Помню в первый раз при приёме большого файла у меня были проблемы с циклом записи из сокета с моим размером буфера, файл не докачивался(кто нибудь знает почему?). Поэтому я с тех пор взял за правило пробивать оптимальный размер буфера для данного сокета с помощью setsockopt(так файл скачается на 100%) и больше не задавался этим вопросом.
          ExpandedWrap disabled
            setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char*)&size,sizeof(int));
            buf = new char [size]="\0";
             
                for(k=0,i=0;i!=SOCKET_ERROR;k+=i)
                {
                    i=recv(sock,buf,sizeof(buf),0);
                    if(i==0) break;
                    здесь складываем в большой буфер, например с помощью memmove, или сначала в файл
                }
            ...
            delete [] buf;
            johen
            Присоединяюсь к словам buggerа и цепляю краткую статейку по "Работа с WinSocket в Visual C++".
            Почитай, поймешь будет проще.
            Прикреплённый файлПрикреплённый файлsysts2.rar (7.29 Кбайт, скачиваний: 287)
              Есть функция TransmitFile() вроде... в Winsock... :unsure:
                Я писал как-то программу для передачи файлов. На делфи и на С. Сейчас гляну ссылку - кому интересно
                ссылка.Там на IPX было. Может кому пригодиться.
                С буфером тоже была проблема - не докачивал большие файлы. Всегда оставались куски.
                После я прочитал, что Посылка данных методом send() не всегда происходит сразу. Он накапливает данные в внутреннем буфере и потом их отсылает. Где-то есть исправленная версия, где все принимается нормально :)
                Сейчас не найду. За примерчик автору спасибо. Особо за http протокол.
                  Если на то пошло, то у меня просьба к Diviner:
                  приведи пожалуйста текст включаемого файла "stdafx.h"
                    Цитата
                    Посылка данных методом send() не всегда происходит сразу. Он накапливает данные в внутреннем буфере и потом их отсылает.

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


                    Рейтинг@Mail.ru
                    [ Script execution time: 0,0416 ]   [ 16 queries used ]   [ Generated: 10.12.24, 12:19 GMT ]