LINUX C 基於TCP/IP協議的SOCKET收發檔案的小例子。
自已沒事正看這方面的東西,感覺要想把網路這塊弄明白還真不是件簡單的事。
程式寫的比較繁瑣,代碼也不合理,有時間再把程式最佳化一下,加上斷點繼傳的功能。。
伺服器端:
/******** http://blog.csdn.net/robertkun ********//******* 伺服器程式 (server.c) ************/// linux 下讀取大於2GB檔案時,需指定#define _FILE_OFFSET_BITS 64#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>#include <fcntl.h>// 定義包的大小為512KB#define PACK_SIZE 1024*512int main(int argc, char *argv[]){// 設定輸出緩衝setvbuf(stdout, NULL, _IONBF, 0);fflush(stdout);int sockfd,new_fd;struct sockaddr_in server_addr;struct sockaddr_in client_addr;int sin_size,portnumber;char hello[]="Hello! Are You Fine?\n";if((portnumber=atoi("8080"))<0){fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);exit(1);}/* 伺服器端開始建立socket描述符 */if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) {fprintf(stderr,"Socket error:%s\n\a",strerror(errno));exit(1);}/* 伺服器端填充 sockaddr結構 */bzero(&server_addr,sizeof(struct sockaddr_in));server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=htonl(INADDR_ANY);server_addr.sin_port=htons(portnumber);/* 捆綁sockfd描述符 */if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) {fprintf(stderr,"Bind error:%s\n\a",strerror(errno));exit(1);}/* 監聽sockfd描述符 */if(listen(sockfd,5)==-1) {fprintf(stderr,"Listen error:%s\n\a",strerror(errno));exit(1);}while(1){fprintf(stderr, "server is listening!\n");/* 伺服器阻塞,直到客戶程式建立串連 */sin_size=sizeof(struct sockaddr_in);if( ( new_fd = accept(sockfd,(struct sockaddr *)(&client_addr),(socklen_t*)&sin_size ) ) == -1) {fprintf(stderr,"Accept error:%s\n\a",strerror(errno));exit(1);}fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));if(write(new_fd,hello,strlen(hello))==-1) {fprintf(stderr,"Write Error:%s\n",strerror(errno));exit(1);}long int read_size = 0;unsigned long file_len = 0;int order_id = 0;char file_name[128] = {'\0'};char file_info[1024] = {'\0'};// 讀取指令printf("\n\nWaiting for read file info!\n");int nn = 0;if(nn = read(new_fd, file_info, 1024)) {// 指令IDint id_h = (int)file_info[0]<<8;order_id = id_h + (int)file_info[1];// 檔案長度// 高16位unsigned long len_hig_1 = 0;memcpy(&len_hig_1, &file_info[2], sizeof(file_info[2]));unsigned long len_hig_2 = 0;memcpy(&len_hig_2, &file_info[3], sizeof(file_info[3]));unsigned long len_hig = len_hig_1 * 256 + len_hig_2;// 低16位unsigned long len_low_1 = 0;memcpy(&len_low_1, &file_info[4], sizeof(file_info[4]));unsigned long len_low_2 = 0;memcpy(&len_low_2, &file_info[5], sizeof(file_info[5]));int len_low = len_low_1 * 256 + len_low_2;file_len = len_hig * 256 * 256 + len_low;// 檔案名稱strncpy(file_name, &file_info[6], strlen(&file_info[6]));printf("order = %d, %lu, %s\n", order_id, file_len, file_name);if((strlen(file_name) == 0) || (file_len == 0)){printf("Read file info error!\n File_name or file_len is zero!\n");close(new_fd);continue;}}else {printf("Read file info error!\n");close(new_fd);close(sockfd);exit(0);}// 寫入檔案printf("\n\nWaiting for read file content!\n");FILE* pf = fopen(file_name, "wb+");if(pf == NULL){printf("Open file error!\n");close(new_fd);continue;}char buff[PACK_SIZE] = {'\0'};while(read_size <= file_len) {//bzero(buff, 1024);int rlen = read(new_fd, buff, PACK_SIZE);if(rlen) {//system("clear");printf("\n\nRead package size = %d\n", rlen);int wn = fwrite(buff, sizeof(char), rlen, pf);read_size += rlen;printf("write file size = %d\n", wn);//printf("Read total size = %d\n", read_size);}else {printf("Read over!...%d\n", rlen);break;}} // End Whileprintf("File len = %ld ... Already read size = %ld\n", file_len, read_size);/* 這個通訊已經結束 */fclose(pf);close(new_fd);/* 迴圈下一個 */}close(sockfd);exit(0);}用戶端:
/******** http://blog.csdn.net/robertkun ********//******* 用戶端程式 client.c ************/// linux 下讀取大於2GB檔案時,需指定#define _FILE_OFFSET_BITS 64#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>#include <sys/stat.h>#include <fcntl.h>// 檔案讀寫// 定義包的大小為512KB#define PACK_SIZE 1024*512char* get_file_name(char* fn);unsigned long get_file_size(const char *path);int main(int argc, char *argv[]){if(argc < 2){printf("please input:<ip> <port> <filePath>.\n");return 0;} // 設定輸出緩衝 setvbuf(stdout, NULL, _IONBF, 0); fflush(stdout);char* filePath = argv[3];if(access(filePath, F_OK) != 0){printf("file not existed!\n");return 0;} int sockfd; char buff[1024] = {'\0'}; struct sockaddr_in server_addr; struct hostent *host; int portnumber,nbytes;const char* ip = argv[1]; if((host=gethostbyname(ip))==NULL) { fprintf(stderr,"Gethostname error\n"); exit(1); }const char* port = argv[2]; if((portnumber=atoi(port))<0) { fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]); exit(1); } /* 客戶程式開始建立 sockfd描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"Socket Error:%s\a\n",strerror(errno)); exit(1); } /* 客戶程式填充服務端的資料 */ bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(portnumber); server_addr.sin_addr=*((struct in_addr *)host->h_addr); /* 客戶程式發起串連請求 */ if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) { fprintf(stderr,"Connect Error:%s\a\n",strerror(errno)); exit(1); } /* 串連成功了 */ if((nbytes=read(sockfd,buff,1024))==-1) { fprintf(stderr,"Read Error:%s\n",strerror(errno)); exit(1); } buff[nbytes]='\0'; printf("I have received:%s\n",buff);/******* 發送指令 ********/bzero(buff,1024);// 指令IDint order = 0x0010;int order_h = order >> 8;buff[0] = (char)order_h;buff[1] = (char)order;// 檔案長度unsigned long len = get_file_size(filePath);printf("file size = %lu\n", len);// 高16位int len_h = len >> 16;int len_h_1 = len_h >> 8;buff[2] = (char)len_h_1;buff[3] = (char)len_h;// 低16位int len_l = len;int len_l_1 = len_l >> 8;buff[4] = (char)len_l_1;buff[5] = (char)len_l;// 檔案名稱char* fileName = get_file_name(filePath);printf("file name = %s\n", fileName);strncpy(&buff[6], fileName, strlen(fileName));write(sockfd,buff,1024); /******* 傳送檔案 ********/printf("file path = %s\n", filePath);FILE* pf = fopen(filePath, "rb");if(pf == NULL) {printf("open file failed!\n");exit(0);}char pack[PACK_SIZE] = {'\0'};while((len = fread(pack, sizeof(char), PACK_SIZE, pf)) > 0) {system("clear");printf("send data size = %d \t", len);write(sockfd, pack, len);bzero(pack,PACK_SIZE);//sleep(1); } /* 結束通訊 */ close(sockfd); exit(0);}char* get_file_name(char* fn){int last = 0;char* pfn = fn+strlen(fn)-1;int i=0;for(i=0; i<strlen(fn); ++i){if(*pfn-- == '/'){last = strlen(fn)-i;break;}}char* name = (char*)malloc(sizeof(char)*256);char* pname = name;int j=0;for(j=last; j<strlen(fn); ++j, ++pname){*pname = fn[j];}return name;}unsigned long get_file_size(const char *path){unsigned int filesize = 0;struct stat statbuff;if(stat(path, &statbuff) < 0) {printf("Get file stat failed!\n");return filesize;}else{filesize = statbuff.st_size;}return filesize;}
MAKEFILE:
伺服器端:
object=server.oserver.o: gcc -g -c server.c gcc -o server $(object)clean: rm server $(object)
用戶端:
object=client.oclient.o: gcc -g -c client.c gcc -o client $(object)clean: rm -rf client $(object)