使用socket tcp實現簡單的檔案傳輸
阿新 • • 發佈:2018-11-10
程式分為server、client兩個部分,client從server獲取檔案。流程如下:
server:
1、建立socket,繫結埠10002,等待client連線;
2、連結後開啟需要傳送的檔案,計算檔案長度併發送長度,等待接收客戶端響應;
3、客戶端響應ok後,傳送檔案資料,傳送緩衝定位8192;
4、傳送結束後關閉連結;
client:
1、建立socket,連結server;
2、接收檔案長度,並回復ok;
3、接收資料並寫入檔案,接收緩衝為8192;
4、接收結束後關閉連結;
參考程式碼如下:
file_server.c:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> #define BUF_SIZE (8192) unsigned char fileBuf[BUF_SIZE]; /* * send file */ void file_server(const char *path) { int skfd, cnfd; FILE *fp = NULL; struct sockaddr_in sockAddr, cltAddr; socklen_t addrLen; unsigned int fileSize; int size, netSize; char buf[10]; if( !path ) { printf("file server: file path error!\n"); return; } //建立tcp socket if((skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } else { printf("socket success!\n"); } //建立結構 繫結地址埠號 memset(&sockAddr, 0, sizeof(struct sockaddr_in)); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); sockAddr.sin_port = htons(10002); //bind if(bind(skfd, (struct sockaddr *)(&sockAddr), sizeof(struct sockaddr)) < 0) { perror("Bind"); exit(1); } else { printf("bind success!\n"); } //listen 監聽 最大4個使用者 if(listen(skfd, 4) < 0) { perror("Listen"); exit(1); } else { printf("listen success!\n"); } /* 呼叫accept,伺服器端一直阻塞,直到客戶程式與其建立連線成功為止*/ addrLen = sizeof(struct sockaddr_in); if((cnfd = accept(skfd, (struct sockaddr *)(&cltAddr), &addrLen)) < 0) { perror("Accept"); exit(1); } else { printf("accept success!\n"); } fp = fopen(path, "r"); if( fp == NULL ) { perror("fopen"); close(cnfd); close(skfd); return; } fseek(fp, 0, SEEK_END); fileSize = ftell(fp); fseek(fp, 0, SEEK_SET); if(write(cnfd, (unsigned char *)&fileSize, 4) != 4) { perror("write"); close(cnfd); close(skfd); exit(1); } if( read(cnfd, buf, 2) != 2) { perror("read"); close(cnfd); close(skfd); exit(1); } while( ( size = fread(fileBuf, 1, BUF_SIZE, fp) ) > 0 ) { unsigned int size2 = 0; while( size2 < size ) { if( (netSize = write(cnfd, fileBuf + size2, size - size2) ) < 0 ) { perror("write"); close(cnfd); close(skfd); exit(1); } size2 += netSize; } } fclose(fp); close(cnfd); close(skfd); } int main(int argc, char **argv) { if( argc < 2 ) { printf("file server: argument error!\n"); printf("file_server /tmp/temp\n"); return -1; } file_server(argv[1]); return 0; }
file_client.c:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> #define BUF_SIZE (8192) unsigned char fileBuf[BUF_SIZE]; void file_client(const char *ip, const char *path) { int skfd; FILE *fp = NULL; struct sockaddr_in sockAddr; unsigned int fileSize, fileSize2; int size, nodeSize; //建立tcp socket if((skfd=socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); exit(1); } else { printf("socket success!\n"); } //建立結構設定待連線的伺服器地址埠號 memset(&sockAddr, 0, sizeof(struct sockaddr_in)); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = inet_addr(ip); sockAddr.sin_port = htons(10002); /* 客戶端呼叫connect主動發起連線請求 */ if(connect(skfd, (struct sockaddr *)(&sockAddr), sizeof(struct sockaddr)) < 0) { perror("ConnectError:"); exit(1); } else { printf("connnect success!\n"); } size = read(skfd, (unsigned char *)&fileSize, 4); if( size != 4 ) { printf("file size error!\n"); close(skfd); exit(-1); } printf("file size:%d\n", fileSize); if( (size = write(skfd, "OK", 2) ) < 0 ) { perror("write"); close(skfd); exit(1); } fp = fopen(path, "w"); if( fp == NULL ) { perror("fopen"); close(skfd); return; } fileSize2 = 0; while(memset(fileBuf, 0, sizeof(fileBuf)), (size = read(skfd, fileBuf, sizeof(fileBuf))) > 0) { unsigned int size2 = 0; while( size2 < size ) { if( (nodeSize = fwrite(fileBuf + size2, 1, size - size2, fp) ) < 0 ) { perror("write"); close(skfd); exit(1); } size2 += nodeSize; } fileSize2 += size; if(fileSize2 >= fileSize) { break; } } fclose(fp); close(skfd); } int main(int argc, char **argv) { if( argc < 3 ) { printf("file client: argument error!\n"); printf("file_client 192.168.1.10 /tmp/temp\n"); return -1; } file_client(argv[1], argv[2]); return 0; }
測試結果:
首先啟動server端,傳送檔案mysql-server-8.0.zip
$ ~/tmp/test/fileserver mysql-server-8.0.zip
再啟動client端,接收此檔案
$ ./fileclient 10.9.0.132 ./mysql.zip
接收成功後解壓這個檔案測試傳輸是否成功。