這是電腦網路課程設計的作品,簡單實現了FTP用戶端。
用winsock2標頭檔。算是socket編程的學習實踐。
所有代碼在vc6.0下調試通過。
/**本程式參考rfc959標準。能與遵守此標準的伺服器進行資訊互動。僅限於windows系統。*/#include < stdio.h >#include < string.h >#include < stdlib.h >/*system()*/#include < winsock2.h >#pragma comment(lib, "ws2_32.lib")#define ONUM 512#define MNUM 512#define FNUM 512#define ptstruct host { char ip[20]; unsigned short port;};SOCKET ts;fd_set readfds;struct timeval timeval;struct host host;char renum[4];char ordertemp[ONUM];char order[ONUM];char ordercp[ONUM];char mess[MNUM];char file[FNUM];char setpath[FNUM];char setpathf[FNUM];int i, door, r, sys, seti;/*i for;door switch;r receive num;sys system state;set set state*/char * p;/*strtok*/int printmess();void input(char ordertemp[]);int ftp();int user();int pass();int command();int list();SOCKET createDataSocket();int set();int retr();int stor();int stor(){ char filename[256]; SOCKET ds; int wi; int r2, r3, r4, bsnum, brnum; FILE * fp = NULL; set(); memset(filename, '\0', 256); memset(order, '\0', ONUM); for (i = 5; i <= 200 && ordercp[i] != '\0'; i++) { order[i - 5] = ordercp[i]; } strcpy(filename, setpathf); strcat(filename, "\\\\"); strcat(filename, order); memset(order, '\0', ONUM); strcpy(order, "type i\r\n"); /*type i 二進位 type a ASCII*/ send(ts, order, strlen(order), 0); switch (printmess()) { case 421: closesocket(ts); sys = 0; return 421; case 530: closesocket(ts); sys = 0; return - 1; case 500: case 501: case 504: case 226: return - 1; case 200: break; default: return - 1; } ds = createDataSocket(); if (ds ==- 1) { return - 1; } strcat(ordercp, "\r\n"); send(ts, ordercp, strlen(ordercp), 0); switch (printmess()) { case 421: closesocket(ds); closesocket(ts); sys = 0; return 421; case 532: case 530: closesocket(ds); closesocket(ts); sys = 0; return - 1; case 450: case 452: case 553: case 500: case 501: closesocket(ds); return - 1; case 125: case 150: break; default: closesocket(ds); return - 1; } fp = fopen(filename, "rb"); if (!fp) { printf("read file fail!\n"); closesocket(ds); return - 1; } r2 = 0; r3 = 0; r4 = 0; bsnum = 0; brnum = 0; wi = 1; while (wi) { memset(file, '\0', FNUM); r = fread(file, sizeof(char), FNUM, fp); if (r == 0) { closesocket(ds); wi = 0; break; } brnum = brnum + r; r3 = r; printf("read %8d bytes! have read %16d bytes!\r", r, brnum); do { r2 = send(ds, file, r3, 0); if (r2 == SOCKET_ERROR) { printf("send file error!"); closesocket(ds); return - 1; } bsnum = bsnum + r2; r3 = r3 - r2; printf("send %8d bytes! have sended %16d bytes!\r", r2, bsnum); } while (brnum > bsnum); }/*while*/ printf("\n"); switch (printmess()) { case 425: case 426: case 451: case 551: case 552: closesocket(ds); fclose(fp); return - 1; case 250: case 226: fclose(fp); return 0; default: return 0; }}/*stor*/int retr(){ char filename[256]; unsigned long fsize, wfsize; int r2, wi; SOCKET ds; FILE * fp = NULL; memset(filename, '\0', 256); memset(order, '\0', ONUM); for (i = 5; i <= 200 && ordercp[i] != '\0'; i++) { order[i - 5] = ordercp[i]; } strcpy(filename, setpathf); strcat(filename, "\\\\"); strcat(filename, order); ds = createDataSocket(); if (ds ==- 1) { return - 1; } memset(order, '\0', ONUM); strcpy(order, "type i\r\n");/*type i 二進位 type a ASCII*/ send(ts, order, strlen(order), 0); switch (printmess()) { case 421: closesocket(ds); closesocket(ts); sys = 0; return 421; case 530: closesocket(ds); closesocket(ts); sys = 0; return - 1; case 500: case 501: case 504: case 226: closesocket(ds); return - 1; case 200: break; default: closesocket(ds); return - 1; } strcat(ordercp, "\r\n"); send(ts, ordercp, strlen(ordercp), 0); switch (printmess()) { case 421: closesocket(ds); closesocket(ts); sys = 0; return 421; case 530: closesocket(ds); closesocket(ts); sys = 0; return - 1; case 450: case 500: case 501: case 550: closesocket(ds); return - 1; case 125: case 150: break; default: closesocket(ds); return - 1; } set(); system(setpath); fp = fopen(filename, "wb"); if (!fp) { printf("create file fail!\n"); closesocket(ds); printmess(); return - 1; } wi = 1; fsize = 0; wfsize = 0; while (wi) { memset(file, '\0', FNUM); r = recv(ds, file, FNUM, 0); if (r == SOCKET_ERROR) { printf("file recv error!\n"); closesocket(ds); fclose(fp); return - 1; } fsize = fsize + r; if (r == 0) { wi = 0; break; } printf("receive %8d bytes! have received %16d bytes!\r", r, fsize); r2 = fwrite(file, sizeof(char), r, fp); // fflush(fp);/*這裡是關鍵*/ wfsize = wfsize + r2; printf("write %8d bytes!have written %20d bytes!\r", r2, wfsize); }/*while*/ printf("\n"); fflush(fp);/*這裡是關鍵*/ switch (printmess()) { case 425: case 426: case 451: closesocket(ds); fclose(fp); return - 1; case 250: case 226: closesocket(ds); wi = 1; while (wi) { if (fclose(fp) == 0) { wi = 0; } return 0; default: closesocket(ds); fclose(fp); return 0;; } }}/*retr()*/int set(){ int n, m; n = 3; m = 0; if (strcmp(order, "set") != 0 && seti == 1) { return 1; } else if (strcmp(order, "set") != 0 && seti == 0) { memset(setpath, '\0', FNUM); memset(setpathf, '\0', FNUM); strcpy(setpath, "md d:\\rhFTPdir"); strcpy(setpathf, "d:\\\\rhFTPdir"); return 2; } memset(setpath, '\0', FNUM); memset(setpathf, '\0', FNUM); memset(order, '\0', ONUM); if (ordercp[5] != ':') { printf("error input!\n"); return - 1; } for (i = 4; i <= 200 && ordercp[i] != '\0'; i++) { order[i - 4] = ordercp[i]; } strcpy(setpath, "md "); for (i = 0; i <= FNUM - 5 && order[i] != '\0'; i++) { if (order[i] == '\\') { strcat(setpath, "\\\\"); n++; strcat(setpathf, "\\\\"); m++; continue; } setpathf[i + m] = order[i]; setpath[i + n] = order[i]; } printf("setpath %s\n", setpath); seti = 1; return 0;}/*set*/int list(){ SOCKET ds; int wi; ds = createDataSocket(); if (ds ==- 1) { return - 1; } strcat(ordercp, "\r\n"); send(ts, ordercp, strlen(ordercp), 0); switch (printmess()) { case 421: closesocket(ds); closesocket(ts); sys = 0; return 421; case 530: closesocket(ds); closesocket(ts); sys = 0; return - 1; case 450: case 500: case 501: case 502: closesocket(ds); return - 1; case 125: case 150: break; default: closesocket(ds); return - 1; } wi = 1; while (wi) { memset(file, '\0', FNUM); r = recv(ds, file, FNUM - 1, 0); if (r == SOCKET_ERROR) { printf("list file recv error!\n"); closesocket(ds); return - 1; } printf("%s", file); if (r == 0) { wi = 0; } } switch (printmess()) { case 425: case 426: case 451: case 226: case 250: closesocket(ds); return 0; default: closesocket(ds); return - 1; }}/*list*/SOCKET createDataSocket(){ char p1[5], p2[5]; unsigned short port; int p1s, p2s; SOCKET ds; struct sockaddr_in server; memset(order, '\0', ONUM); /*pasv*/ strcpy(order, "pasv\r\n"); send(ts, order, strlen(order), 0); r = printmess(); if (r ==- 1 || r != 227) { return - 1; } memset(p1, '\0', 5); memset(p2, '\0', 5); p1s = 0; p2s = 0; for (i = 0, r = 0; i < 200 && mess[i] != '\0'; i++) { if (mess[i] == ',') { r++; continue; } if (r == 4) { p1[p1s] = mess[i]; p1s++; continue; } if (r == 5) { p2[p2s] = mess[i]; p2s++; continue; } } port = atoi(p1) * 256 + atoi(p2); printf("port:%d\n", port); server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.S_un.S_addr = inet_addr(host.ip); ds = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /*TCP*/ if (ds ==- 1) { printf("Failed socket() in createDataSocket()\n"); return - 1; } r = connect(ds, (struct sockaddr * ) & server, sizeof(server)); if (r == SOCKET_ERROR) { printf("connect error in createDataSocket()!\n"); closesocket(ds); return - 1; } return ds;}/*createDataSocket()*/int command(){ strcat(ordercp, "\r\n"); send(ts, ordercp, strlen(ordercp), 0); switch (printmess()) { case 421: closesocket(ts); sys = 0; return 421; case 221: closesocket(ts); sys = 0; return 221; case 530: closesocket(ts); sys = 0; return 0; case 200: case 250: case 450: case 550: case 500: case 501: case 502: return 0; default: return - 1; }}/*command*/int pass(){ strcat(ordercp, "\r\n"); send(ts, ordercp, strlen(ordercp), 0); switch (printmess()) { case 421: closesocket(ts); sys = 0; return 421; case 530: closesocket(ts); sys = 0; return 0; case 500: case 501: case 503: case 202: return 0; case 332: sys = 1; return 0; case 230: sys = 3; return 0; default: return - 1; }}/*pass*/int user(){ if (ordercp[5] == '-') { strcat(order, " anonymous\r\n"); send(ts, order, strlen(order), 0); } else { strcat(ordercp, "\r\n"); send(ts, ordercp, strlen(ordercp), 0); } switch (printmess()) { case 421: closesocket(ts); sys = 0; return 421; case 530: closesocket(ts); sys = 0; return 0; case 230: sys = 3; return 0; case 500: case 501: case 332: return 0; case 331: sys = 2; return 0; default: return - 1; }}/*user*/int ftp(){ WSADATA wsaData; struct sockaddr_in serveraddr; if (sys != 0) { printf("please bye first!\n"); return 0; } WSAStartup(MAKEWORD(2, 2), & wsaData); /*建立與Socket庫綁定*/ ts = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /*TCP*/ if (ts ==- 1) { printf("Failed socket()\n"); WSACleanup(); return - 1; } memset(host.ip, '\0', 20); p = strtok(NULL, " "); strcpy(host.ip, p); p = strtok(NULL, " "); if (p == NULL) { host.port = 21; } else { host.port = atoi(p); } serveraddr.sin_family = AF_INET; /*主機地址標識*/ serveraddr.sin_port = htons(host.port); /*port htons 16*/ serveraddr.sin_addr.S_un.S_addr = inet_addr(host.ip); /*ip*/ r = connect(ts, (struct sockaddr * ) & serveraddr, sizeof(serveraddr)); /*發送串連請求*/ if (r == SOCKET_ERROR) { printf("connect error!\n"); return - 1; } switch (printmess()) { case 220: sys = 1; return 0; case 120: while (printmess() == 220) { sys = 1; return 0; } case 421: closesocket(ts); sys = 0; return 421; case - 1: return - 1; default: return - 1; }}/*ftp*/int printmess(){ int p, n, wi; p = 0; n = 0; wi = 1; memset(renum, '\0', 4); FD_ZERO(&readfds); /*select*/ FD_SET(ts, & readfds); r = select(0, & readfds, NULL, NULL, & timeval); while (r > 0 && FD_ISSET(ts, & readfds) && wi == 1) { memset(mess, '\0', MNUM); r = recv(ts, mess, MNUM - 1, 0); if (r == SOCKET_ERROR) { printf("printmess recv error!\n"); return - 1; } if (p == 0) { strncpy(renum, mess, 4); n = atoi(renum); p = 1; } printf("%s", mess); FD_ZERO(&readfds); /*select*/ FD_SET(ts, & readfds); r = select(0, & readfds, NULL, NULL, & timeval); if (r == 0) { wi = 0; } } return n;}/*printmess()*/void input(char ordertemp[]){ for (i = 0; i < ONUM; i++) { ordertemp[i] = getchar(); if (ordertemp[i] == 10) { ordertemp[i] = '\0'; break; } /*10 enter*/ } if (ordertemp[0] != '\0') { strcpy(ordercp, ordertemp); p = NULL; p = strtok(ordertemp, " "); strcpy(order, p); strlwr(order); }}/*input*/int main(){ int wi; seti = 0; timeval.tv_sec = 0; /*5000ms 避免死結*/ timeval.tv_usec = 500000; printf("** Welcome to use RedHaw FTPclient! **\n"); sys = 0; /*0-初始 1-接收user 2-接收pass 3-接收其他command*/ wi = 1; while (wi) { memset(ordertemp, '\0', ONUM); memset(order, '\0', ONUM); memset(ordercp, '\0', ONUM); switch (sys) { case 0: printf("+ ftp <host-ip> [port] + exit +\n"); break; case 1: printf("+ user <username> Tip:\" \'-\' for anonymous \" +\n"); break; case 2: printf("+ pass <password> Tip:\" \'-\' for anonymous \" +\n"); break; default: printf("+ help|list|cdup|cwd <dir>|mkd <>|rmd <>|set <dir> +\n"); printf("+ user|quit|exit|retr <down>|stor <up>|dele <file> +\n"); } printf("rhFTP>"); input(ordertemp); if (ordertemp[0] == '\0') { continue; } if (strcmp(order, "ftp") == 0 && sys == 0) { door = 1; } /*1 ftp */ else if (strcmp(order, "user") == 0 && (sys == 1 || sys == 3)) door = 2; /*2 user*/ else if (strcmp(order, "pass") == 0 && sys == 2) door = 3; /*3 pass*/ else if (strcmp(order, "quit") == 0 && sys == 3) door = 4; /*4 quit*/ else if (strcmp(order, "exit") == 0 && (sys == 0 || sys == 3)) door = 5; /*5 exit*/ else if (strcmp(order, "list") == 0 && sys == 3) door = 6; /*6 list*/ else if (strcmp(order, "cwd") == 0 && sys == 3) door = 7; /*7 cwd */ else if (strcmp(order, "dele") == 0 && sys == 3) door = 8; /*8 dele*/ else if (strcmp(order, "retr") == 0 && sys == 3) door = 9; /*9 retr*/ else if (strcmp(order, "set") == 0 && sys == 3) door = 10; /*10 set */ else if (strcmp(order, "stor") == 0 && sys == 3) door = 11; /*11 stor*/ else if (strcmp(order, "cdup") == 0 && sys == 3) door = 12; /*12 cdup*/ else if (strcmp(order, "help") == 0 && sys == 3) door = 13; /*13 help*/ else if (strcmp(order, "mkd") == 0 && sys == 3) door = 14; /*14 mkd */ else if (strcmp(order, "rmd") == 0 && sys == 3) door = 15; /*15 rmd */ else door = 0; switch (door) { case 0: printf("Disallowed command!\n"); break; case 1: r = ftp(); break; case 2: r = user(); break; case 3: r = pass(); break; case 4: r = command(); break; case 5: if (sys == 3) { memset(ordercp, '\0', ONUM); strcpy(ordercp, "quit\r\n"); command(); closesocket(ts); } wi = 0; break; case 13: case 6: r = list(); break; case 12: case 14: case 15: case 7: case 8: r = command(); break; case 9: r = retr(); break; case 10: r = set(); break; case 11: r = stor(); break; default: wi = 0; break; } /*switch(door)*/ } /*while(wi)*/ WSACleanup(); return 0;}/*main*/
- by 一個農夫 -