Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Trang 1 của 2 12 CuốiCuối
Kết quả 1 đến 10 của 11
  1. #1
    Ngày tham gia
    Sep 2015
    Bài viết
    0

    Lệnh PORT của FTP trong VC++ xử lý thế nào?

    Em đang làm một cái FTP cilent có nhiệm vụ duy nhất là upload file lên host .Em đang gặp vấn đề với lệnh PORT để khởi tạo kênh dữ liệu cho giao dịch, đây là hàm để đăng nhập và gửi lệnh PORT lên sever :

    Mã:
    char* getip(char *hostname){    HOSTENT *host;    char ip[MAX_PATH];    IN_ADDR **data;    host=gethostbyname(hostname);    if(host==NULL){return "error";}    data=(IN_ADDR**)host->h_addr_list;    return inet_ntoa(**data);} BOOL recvorsend(SOCKET sock,BOOL choice,char* order){    int re,rel;    DWORD er;    rel=0;    if(choice){    char answer[MAX_PATH],*translate;    while(TRUE){    Sleep(200);    re=recv(sock,answer,sizeof(answer),MSG_PEEK);    if(rel==0){rel=re;continue;}    if(re!=rel){continue;}else{break;}    }    re=recv(sock,answer,sizeof(answer),0);    er=GetLastError();    translate=(char*)calloc(re+1,sizeof(char));    strncpy(translate,answer,re);    translate[re+1]='\0';    if(re!=SOCKET_ERROR){cout<<translate;return TRUE;}else{cout<<"error recving answer from host"<<endl;return FALSE;}    }else{        char command[MAX_PATH],*addition="
    ";        int len;        if(order==NULL){getvalue(command,TRUE);}else{strcpy(command,order);}        if(!strcmp(command,"close connect")){return FALSE;}        len=strlen(command);        command[len+1]='\0';        command[len]='
    ';        re=send(sock,command,strlen(command),0);        er=GetLastError();        if(re!=SOCKET_ERROR){return TRUE;}else{return FALSE;}    }} DWORD WINAPI createDATACHANNEL(LPVOID port){    int re;    SOCKET sock,sockdata;    SOCKADDR_IN data;    sock=sockcreate(SOCK_STREAM);    data.sin_addr.S_un.S_addr=INADDR_ANY;    data.sin_family=AF_INET;    data.sin_port=htons((int)port);    if(bind(sock,(sockaddr*)&data,sizeof(data))==SOCKET_ERROR){cout<<"error bind port"<<endl;return 0;}    if(listen(sock,3)==SOCKET_ERROR){cout<<"error listen"<<endl;return 0;}    sockdata=accept(sock,NULL,NULL);    if(sockdata==INVALID_SOCKET){cout<<"error accetting socket error"<<endl;return 0;}else{cout<<sockdata<<endl;return 12;}} BOOL loginandport(SOCKET sock,char *user,char *pass,int port){    char command[MAX_PATH];    SOCKET sockdata;    HANDLE thread;    DWORD id;    char *ip=getip("");    recvorsend(sock,TRUE,NULL);    strcpy(command,"user ");    strcat(command,user);    if(!recvorsend(sock,FALSE,command)){return FALSE;}    recvorsend(sock,TRUE,NULL);    Sleep(500);    strcpy(command,"pass ");    strcat(command,pass);    if(!recvorsend(sock,FALSE,command)){return FALSE;}    recvorsend(sock,TRUE,NULL);    Sleep(500);    thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)createDATACHANNEL,(LPVOID)port,0,&id);    Sleep(100);    strcpy(command,tranportcom(ip,port));    if(!recvorsend(sock,FALSE,command)){return FALSE;}    GetExitCodeThread(thread,&id);    sockdata=(SOCKET)id;    while(id==STILL_ACTIVE){    GetExitCodeThread(thread,&id);    sockdata=(SOCKET)id;    }    recvorsend(sock,TRUE,NULL);    return TRUE;}}
    Hàm loginandport và cái thread của em không biết có sai gì không nhưng khi chạy thì đợi dài cổ mà chảng thấy sever trả lời trên kênh dòng lệnh.Và một vấn đề nữa là nếu em DEBUG để chạy từng dòng lệnh thì trên Console chạy ra được thế này

    còn nếu nhấn Ctrl+F5 cho nó tự chạy thì chỉ được tới đây là đơ , mấy bác xem giùm em thử chớ em chạy với sửa code gàn chục lần rồi mà nó vẫn cứ đơ ra như thế [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

    *:em đang dùng VS 2005.

  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Lệnh port để thông báo cho server biết cổng cần nhận dữ liệu trên client, khi đó server sẽ kết nối tới cổng này và send dữ liệu. Tuy nhiên, nếu bạn sử dụng phương pháp này thì lại gặp vấn đề chuyển đổi địa chỉ. Server chỉ biết IP của bạn khi kết nối, đó là IP của router nằm giữa bạn và server, muốn chuyển dữ liệu từ router về máy tính thì địa chỉ lại khác ( bạn tìm hiểu cơ chế NAT ) . Vì thế trên router của bạn phải hỗ trợ forward port đồng thời bạn phải sử dụng giao thức uPnP để cấu hình router. Tóm lại là cực kì vất vả và phức tạp

    để chuyển dữ liệu, bạn nên tìm hiểu lệnh PASV

  3. #3
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Em đã Gửi lệnh PASV trong hàm này rồi

    Mã:
    SOCKET createDATACHANNEL(SOCKET sock){    SOCKET sockcon;    SOCKADDR_IN data;    char command[MAX_PATH],info[MAX_PATH];    int bg,en,doc;    doc=0;    strcpy(command,"PASV");    recvorsend(sock,FALSE,(char*)&command);    recvorsend(sock,TRUE,(char*)&command);    for(int i=0;i<=strlen(command);i++){        if(command[i]=='('){bg=i;}        if(command[i]==')'){en=i;}    }    strcpy(info,copya(command,bg+1,en-bg-1));    for(int i=1;i<=strlen(info);i++){        if(info[i]==','){info[i]='.';}    }    strcpy(info,scannum(info,&bg,&en));    sockcon=sockcreate(SOCK_STREAM);    if(!connecthost(info,sockcon,bg*256+en)){return SOCKET_ERROR;}else{        return sockcon;    }}
    cái biến sock chính là socket của kênh dữ liệu đã được khởi tạo.Em đã làm cho nó úp được file lên mạng rồi nhưng tốc độ truyền thấp quá, cho em hỏi ở chế độ BINARY thì em chỉ được truyền mỗi lần một bit dưới dạng char thôi hả anh? Hay là có thể truyền nhiều bit cùng lúc dứơi dạng char?

  4. #4
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Ở chế độ này, mỗi lần truyền 1 byte thì phải, nó y hệt việc send và recv dữ liệu thường thôi bạn ạ, cũng không quan trọng lắm đâu

    cái cần quan tâm là kịch bản truyền nhận file cơ

    Khi nhận file :
    bước 1 là có tên file trên server , dùng lệnh size để lấy kích thước
    bước 2: dùng pasv để khởi động chế độ passive mode, server trả về cho mình IP và port để kết nối, mình phải nhận giá trị này trên control connection. 1 số server của tàu sử dụng các kí tự khác, + 1 số thông tin khác nữa trong lần trả về này nên bước parse IP và port cực kì quan trọng, nếu muốn chương trình không bị chết, bạn phải test với cực nhiều server
    bước 3: sử dùng lệnh RETR trên control connection, khi đó chỉ cần kết nối tới địa chỉ được trả về sau lệnh pasv là có dữ liệu

    với gửi dữ liệu, chỉ cần thực hiện 2 bước 2 và 3, và dùng lệnh STOR để lưu file

    thứ tự các bước phải tuần tự như trên, không được sai

  5. #5
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trích dẫn Gửi bởi quangnh89
    Lệnh port để thông báo cho server biết cổng cần nhận dữ liệu trên client, khi đó server sẽ kết nối tới cổng này và send dữ liệu. Tuy nhiên, nếu bạn sử dụng phương pháp này thì lại gặp vấn đề chuyển đổi địa chỉ. Server chỉ biết IP của bạn khi kết nối, đó là IP của router nằm giữa bạn và server, muốn chuyển dữ liệu từ router về máy tính thì địa chỉ lại khác ( bạn tìm hiểu cơ chế NAT ) . Vì thế trên router của bạn phải hỗ trợ forward port đồng thời bạn phải sử dụng giao thức uPnP để cấu hình router. Tóm lại là cực kì vất vả và phức tạp

    để chuyển dữ liệu, bạn nên tìm hiểu lệnh PASV
    Cảm ơn anh đã trả lời giúp em, em đã chuyển đổi dạng kết nối và chương trình đã chạy được như mong muốn. Em muốn hỏi thêm là trong FTP có dạng truyền dữ liệu la ASCII và BINARY , em viết hàm để thực hiện việc truyền file theo 2 kiểu như sau :

    Mã:
    BOOL upanddown(SOCKET sock,char* command,BOOL choice){    char dircilent[MAX_PATH],dirsever[MAX_PATH],com[MAX_PATH],y;    SOCKET sockdata;    ofstream file;    int space[2],sl;    BOOL type;    sl=0;    if(choice){        for (int i=0;i<=strlen(command)-1;i++){            if(command[i]==' '){                space[sl]=i;                sl++;            }        }        if(sl>=3){return FALSE;}        if(sl==2){            strcpy(dircilent,copya(command,space[0]+1,space[1]-space[0]-1));            strcpy(dirsever,copya(command,space[1]+1,strlen(command)-space[1]-1));          }        file.open(dircilent,ios::in);        if(file.fail()){cout<<"file not found"<<endl;return FALSE;}        file.close();        strcpy(com,"SIZE ");        strcat(com,dirsever);        if(!recvorsend(sock,FALSE,com)){cout<<"error send command"<<endl;goto close;(sockdata);return FALSE;}        if(!recvorsend(sock,TRUE,(char*)&com)){cout<<"error recv answer from sever"<<endl;goto close;}        if(strsearch("213",com,FALSE)){             cout<<"There is a file has the same name on the sever , do yo want to overwrite it(y=yes=no): ";            y=getchar();            if(y=='y'){goto starttranfer;}else{return FALSE;}        }starttranfer:        type=checkfiletype(dircilent);        if(type){            strcpy(com,"TYPE A");            if(!recvorsend(sock,FALSE,com)){cout<<"error send command"<<endl;goto close;}            if(!recvorsend(sock,TRUE,(char*)&com)){cout<<"error recv answer from sever"<<endl;goto close;}        }else{            strcpy(com,"TYPE I");            if(!recvorsend(sock,FALSE,com)){cout<<"error send command"<<endl;goto close;}            if(!recvorsend(sock,TRUE,(char*)&com)){cout<<"error recv answer from sever"<<endl;goto close;}        }        sockdata=createDATACHANNEL(sock);        strcpy(com,"STOR ");        strcat(com,dirsever);        if(!recvorsend(sock,FALSE,com)){cout<<"error send command"<<endl;goto close;}        transfers(sockdata,dircilent,type);        if(!recvorsend(sock,TRUE,(char*)&com)){cout<<"error recv answer from sever"<<endl;goto close;}        closesocket(sockdata);        if(!recvorsend(sock,TRUE,(char*)&com)){cout<<"error recv answer from sever"<<endl;return FALSE;}        return TRUE;        close:        closesocket(sockdata);        if(!recvorsend(sock,TRUE,(char*)&com)){cout<<"error recv answer from sever"<<endl;return FALSE;}        return FALSE;    }        return TRUE;    }
    Cho em hỏi là vì sao em upload file dưới dạng ASCII hay BINARY thì sever đều báo truyền file thành công nhưng sau khi upload em dung lenh list để xem thư mục thì không tìm thấy file đã truyền , có phải hàm hàm em viết có vấn đề ?

  6. #6
    Trích dẫn Gửi bởi dragon124
    Cảm ơn anh đã trả lời giúp em, em đã chuyển đổi dạng kết nối và chương trình đã chạy được như mong muốn. Em muốn hỏi thêm là trong FTP có dạng truyền dữ liệu la ASCII và BINARY , em viết hàm để thực hiện việc truyền file theo 2 kiểu như sau :

    Cho em hỏi là vì sao em upload file dưới dạng ASCII hay BINARY thì sever đều báo truyền file thành công nhưng sau khi upload em dung lenh list để xem thư mục thì không tìm thấy file đã truyền , có phải hàm hàm em viết có vấn đề ?
    trong code không thấy bạn định nghĩa cách truyền dữ liệu là PASV

  7. #7
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trích dẫn Gửi bởi meoconlongvang
    char *trans chưa được cấp phát.
    em đã cấp phát nó ở dòng đầu tiên sau lệnh if rồi mà

  8. #8
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Đây là hàm truyền dữ liệu của em
    Mã:
    BOOL transfers(SOCKET sockdata,char *filename,BOOL up,BOOL dis,DWORD size){
    	fstream file;
    	char *trans;
    	int d,sum;
    	float per;
    	per=0;
    	sum=0;
    	if(up){
    		trans=(char*)calloc(10,sizeof(char));
    		file.open(filename,ios::in|ios::binary);
    		file.seekg(ios::beg);
    		do{
    			file.read(trans,10);
    			d=send(sockdata,trans,10,0);
    			if((d==SOCKET_ERROR)||(d==0)){return FALSE;}
    		}while(!file.eof());	
    		file.close();
    	}
    	return TRUE;
    }
    cho em hỏi nó có vô lí chỗ nào không mà sao cứ xuất hiện lỗi:
    [IMG]http:/d3.upanh.com/b4.s1.d1/dbeaf7a8048089fcb25776d801ca1870_35754033.untitled dddd.bmp[/IMG]
    Bác nào xem giúp em với[IMG]images/smilies/Cry.gif[/IMG]

  9. #9
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    char *trans chưa được cấp phát.

  10. #10
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    em đã sửa lại code như sau
    Mã:
    BOOL transfers(SOCKET sockdata,char *filename,BOOL up,BOOL dis,DWORD size){
    	fstream file;
    	char *trans;
    	int d;
    	if(up){
    		d=0;
    		trans=(char*)calloc(200,sizeof(char));
    		file.open(filename,ios::in|ios::binary);
    		do{
    			file.read(trans,100);
    			d=send(sockdata,trans,100,0);
    			if((d==SOCKET_ERROR)||(d==0)){return FALSE;}
    		}while(!file.eof());	
    		file.close();
    	}
    	free(trans);
    	return TRUE;
    }
    Code chạy được trên debug + release nhưng đến khi xuất ra file cuối cùng để chạy thì lại lỗi [IMG]images/smilies/Cry.gif[/IMG][IMG]images/smilies/Cry.gif[/IMG] em kiểm tra lại thì thấy lỗi tại hàm
    Mã:
    file.read(trans,100);
    và khi tiếp tuc debug thì tìm được câu lệnh bị lỗi ở hàm _mbstowcs_l_helper của mbstowcs.c
    Mã:
    extern "C" size_t __cdecl _mbstowcs_l_helper (
            wchar_t  *pwcs,
            const char *s,
            size_t n,
            _locale_t plocinfo
            )
    {
        size_t count = 0;
    
        if (pwcs && n == 0)
            /* dest string exists, but 0 bytes converted */
            return (size_t) 0;
    
        if (pwcs && n > 0)
        {
            *pwcs = '\0';
        }
    
        /* validation section */
        _VALIDATE_RETURN(s != NULL, EINVAL, (size_t)-1);
        /* n must fit into an int for MultiByteToWideChar */
        _VALIDATE_RETURN(n <= INT_MAX, EINVAL, (size_t)-1);
    
    
        _LocaleUpdate _loc_update(plocinfo);
        /* if destination string exists, fill it in */
        if (pwcs) chạy tới đây thì bị lỗi Unhandled exception at 0x7c911689 in ftp.exe: 0xC0000005: Access violation reading location 0x00000000.
        {
            if (_loc_update.GetLocaleT()->locinfo->lc_handle[LC_CTYPE] == _CLOCALEHANDLE)
            {
                /* C locale: easy and fast */
                while (count < n)
                {
                    *pwcs = (wchar_t) ((unsigned char)s[count]);
                    if (!s[count])
                        return count;
                    count++;
                    pwcs++;
                }
                return count;
    
            } else {
                int bytecnt, charcnt;
                unsigned char *p;
    
                /* Assume that the buffer is large enough */
                if ( (count = MultiByteToWideChar( _loc_update.GetLocaleT()->locinfo->lc_codepage,
                                                   MB_PRECOMPOSED |
                                                    MB_ERR_INVALID_CHARS,
                                                   s,
                                                   -1,
                                                   pwcs,
                                                   (int)n )) != 0 )
                    return count - 1; /* don't count NUL */
    
                if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
                {
                    errno = EILSEQ;
                    *pwcs = '\0';
                    return (size_t)-1;
                }
    
                /* User-supplied buffer not large enough. */
    
                /* How many bytes are in n characters of the string? */
                charcnt = (int)n;
                for (p = (unsigned char *)s; (charcnt-- && *p); p++)
                {
                    if (
                        _isleadbyte_l(*p, _loc_update.GetLocaleT())
                        )
                    {
                        if(p[1]=='\0')
                        {
                            /*  this is a leadbyte followed by EOS -- a dud MBCS string
                                We choose not to assert here because this
                                function is defined to deal with dud strings on
                                input and return a known value
                            */
                            errno = EILSEQ;
                            *pwcs = '\0';
                            return (size_t)-1;
                        }
                        else
                        {
                            p++;
                        }
                    }
                }
                bytecnt = ((int) ((char *)p - (char *)s));
    
                if ( (count = MultiByteToWideChar( _loc_update.GetLocaleT()->locinfo->lc_codepage,
                                                   MB_PRECOMPOSED,
                                                   s,
                                                   bytecnt,
                                                   pwcs,
                                                   (int)n )) == 0 )
                {
                    errno = EILSEQ;
                    *pwcs = '\0';
                    return (size_t)-1;
                }
    
                return count; /* no NUL in string */
            }
        }
        else { /* pwcs == NULL, get size only, s must be NUL-terminated */
            if (_loc_update.GetLocaleT()->locinfo->lc_handle[LC_CTYPE] == _CLOCALEHANDLE) {
                return strlen(s);
            } else if ( (count = MultiByteToWideChar( _loc_update.GetLocaleT()->locinfo->lc_codepage,
                                                      MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
                                                      s,
                                                      -1,
                                                      NULL,
                                                      0 )) == 0 ) {
                errno = EILSEQ;
                return (size_t)-1;
            } else {
                return count - 1;
            }
        }
    
    }
    cho em hỏi lỗi trên gì và có thể khắc phục bằng cách nào ? mấy anh chị giúp em với , em làm cái này 2 tháng rồi mà giờ vẫn chưa xong cứ Debug được thì qua realese lại lỗi [IMG]images/smilies/Cry.gif[/IMG][IMG]images/smilies/Cry.gif[/IMG][IMG]images/smilies/21.gif[/IMG]

 

 
Trang 1 của 2 12 CuốiCuối

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •