Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.14.84] |
|
Сообщ.
#1
,
|
|
|
Прошу привести простой пример передачи файлов между клиентом и сервером, используя сокеты и чистый WinAPI (не используя MFC). Пример должен быть консольной прогой.
Спасибо. |
Сообщ.
#2
,
|
|
|
как это не банально, но совет будет такой: лучше прочитай книжку по сетевому программированию. там все подробно разложено и рассказано. учиться программировать сетевое приложение в форуме - это очень ненадежно, так как у тебя так и не появится четкого понимания, а знания ты будешь вырывать кусками.
Цитата лучше потратить неделю, а потом за пять минут долететь... |
Сообщ.
#3
,
|
|
|
Совет хороший дал bugger.
У меня есть пара минут свободных, поэтому покажу простой пример. Ну прежде всего johen тебе надо определиться с протоколом (протоколом уровня приложений если по научному), мне кажется не стоит чего-то там своего изобретать, типа придумывать свои ключевые слова или байты, а стоит воспользоваться HTTP или FTP протоколом. Когда-то смотрел, что там IExplorer посылает, получилась такая консольная програмка: #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%) и больше не задавался этим вопросом. 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; |
Сообщ.
#4
,
|
|
|
johen
Присоединяюсь к словам buggerа и цепляю краткую статейку по "Работа с WinSocket в Visual C++". Почитай, поймешь будет проще. Прикреплённый файлsysts2.rar (7.29 Кбайт, скачиваний: 287) |
Сообщ.
#5
,
|
|
|
Есть функция TransmitFile() вроде... в Winsock...
|
Сообщ.
#6
,
|
|
|
Я писал как-то программу для передачи файлов. На делфи и на С. Сейчас гляну ссылку - кому интересно
ссылка.Там на IPX было. Может кому пригодиться. С буфером тоже была проблема - не докачивал большие файлы. Всегда оставались куски. После я прочитал, что Посылка данных методом send() не всегда происходит сразу. Он накапливает данные в внутреннем буфере и потом их отсылает. Где-то есть исправленная версия, где все принимается нормально Сейчас не найду. За примерчик автору спасибо. Особо за http протокол. |
Сообщ.
#7
,
|
|
|
Если на то пошло, то у меня просьба к Diviner:
приведи пожалуйста текст включаемого файла "stdafx.h" |
Сообщ.
#8
,
|
|
|
Цитата Посылка данных методом send() не всегда происходит сразу. Он накапливает данные в внутреннем буфере и потом их отсылает. Вроде логично ведь send() это не блокирующая функция, а посему для получения сообщения об отправке нужно обрабатывать WSAEnumNetworkEvents(). |